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

feat(contextual-help): add contextual help pattern #4285

Merged
merged 22 commits into from
Jun 3, 2024
Merged

Conversation

Rocss
Copy link
Contributor

@Rocss Rocss commented Apr 22, 2024

Description

Adds @spectrum-web-components/contextual-help, as per https://spectrum.adobe.com/page/contextual-help/

Related issue(s)

Motivation and context

Contextual help is a pattern used widely across Adobe apps. Even if at its core it is a simple component, the lack of a reusable component around this pattern results in different teams implementing different versions of it.
Differences in implementation differ not only on the visual level, but also on the accessibility and mobile responsiveness level. Current implementations are some of them lacking keyboard navigation support, screen reader support, and not taking into consideration user experience on mobile devices.

How has this been tested?

  • Test case 1
    1. Go here
    2. Open/close the Contextual help component
    3. UI respects the spectrum-css styling
  • Test case 2
    1. Go here
    2. Toggle between info/help variants
    3. Observe the icon is changing from informative to help
  • Test case 3
    1. Go here
    2. Change the placement prop using the Storybook Controls Addon
    3. Observe the popover is positioned based on the placement prop
  • Test case 4
    1. Go here
    2. Switch to responsive mode -> choose a mobile view
    3. Observe the Contextual help is opening a dialog on mobile, instead of a popover
  • Test case 5
    1. Go here
    2. Check out controlled behaviour by toggling the open control

Screenshots (if appropriate)

Screenshot 2024-04-22 at 11 28 57

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Chore (minor updates related to the tooling or maintenance of the repository, does not impact compiled assets)

Checklist

  • I have signed the Adobe Open Source CLA.
  • My code follows the code style of this project.
  • If my change required a change to the documentation, I have updated the documentation in this pull request.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • I have reviewed at the Accessibility Practices for this feature, see: Aria Practices

Best practices

This repository uses conventional commit syntax for each commit message; note that the GitHub UI does not use this by default so be cautious when accepting suggested changes. Avoid the "Update branch" button on the pull request and opt instead for rebasing your branch against main.

Copy link

github-actions bot commented Apr 22, 2024

Branch preview

Visual regression test results

When a visual regression test fails (or has previously failed while working on this branch), its results can be found in the following URLs:

Copy link

github-actions bot commented Apr 22, 2024

Lighthouse scores

Category Latest (report) Main (report) Branch (report)
Performance 0.99 0.99 0.99
Accessibility 1 1 1
Best Practices 1 1 1
SEO 1 0.92 0.92
PWA 1 1 1
What is this?

Lighthouse scores comparing the documentation site built from the PR ("Branch") to that of the production documentation site ("Latest") and the build currently on main ("Main"). Higher scores are better, but note that the SEO scores on Netlify URLs are artifically constrained to 0.92.

Transfer Size

Category Latest Main Branch
Total 224.097 kB 210.69 kB 🏆 210.695 kB
Scripts 53.43 kB 48.317 kB 🏆 48.395 kB
Stylesheet 34.839 kB 30.472 kB 30.373 kB 🏆
Document 5.996 kB 5.268 kB 🏆 5.312 kB
Font 126.953 kB 126.633 kB 126.615 kB 🏆

Request Count

Category Latest Main Branch
Total 48 45 45
Scripts 37 37 37
Stylesheet 5 5 5
Document 1 1 1
Font 2 2 2

Copy link

github-actions bot commented Apr 22, 2024

Tachometer results

Chrome

color-field permalink

basic-test

Version Bytes Avg Time vs remote vs branch
npm latest 487 kB 41.05ms - 43.29ms - unsure 🔍
-6% - +1%
-2.59ms - +0.46ms
branch 475 kB 42.21ms - 44.27ms unsure 🔍
-1% - +6%
-0.46ms - +2.59ms
-

combobox permalink

basic-test

Version Bytes Avg Time vs remote vs branch
npm latest 709 kB 35.45ms - 36.41ms - faster ✔
3% - 6%
1.17ms - 2.31ms
branch 696 kB 37.37ms - 37.97ms slower ❌
3% - 6%
1.17ms - 2.31ms
-

light-dom-test permalink

Version Bytes Avg Time vs remote vs branch
npm latest 710 kB 386.18ms - 392.60ms - faster ✔
3% - 5%
10.36ms - 20.16ms
branch 697 kB 400.95ms - 408.35ms slower ❌
3% - 5%
10.36ms - 20.16ms
-
Firefox

color-field permalink

basic-test

Version Bytes Avg Time vs remote vs branch
npm latest 495 kB 75.74ms - 78.62ms - unsure 🔍
-6% - +0%
-4.78ms - +0.26ms
branch 483 kB 77.37ms - 81.51ms unsure 🔍
-0% - +6%
-0.26ms - +4.78ms
-

combobox permalink

basic-test

Version Bytes Avg Time vs remote vs branch
npm latest 709 kB 61.74ms - 68.78ms - slower ❌
1% - 13%
0.51ms - 7.93ms
branch 696 kB 59.88ms - 62.20ms faster ✔
1% - 12%
0.51ms - 7.93ms
-

light-dom-test permalink

Version Bytes Avg Time vs remote vs branch
npm latest 710 kB 717.68ms - 740.00ms - slower ❌
2% - 6%
15.05ms - 40.03ms
branch 697 kB 695.69ms - 706.91ms faster ✔
2% - 5%
15.05ms - 40.03ms
-

@Rocss Rocss changed the title feat(contextual-help): add ContextualHelp component feat(contextual-help): add contextual help pattern Apr 22, 2024
@Rocss Rocss marked this pull request as ready for review April 22, 2024 09:27
@Rocss
Copy link
Contributor Author

Rocss commented Apr 22, 2024

I'm marking it as ready for review even if unit tests are incomplete, because I am looking for a high level review of this current implementation, and any changes would make the tests obsolete.

I found this component to be a good use case for the slottable-request pattern. However, if this seems overkill given the small contents of the popover I can get rid of it.

I'm looking for comments on the width / max-width dilema: #4281 (comment), as well as on the mobile behaviour.

@Rocss Rocss requested a review from Rajdeepc April 22, 2024 09:32
Copy link
Contributor

@Westbrook Westbrook left a comment

Choose a reason for hiding this comment

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

You can confirm the args and template sharing by seeing the demo published at the top of the docs site after the change.

packages/contextual-help/src/ContextualHelp.ts Outdated Show resolved Hide resolved
<section>
${this.headline &&
html`
<h2 class="heading">${this.headline}</h2>
Copy link
Contributor

Choose a reason for hiding this comment

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

A user should have control over the heading level leveraged here. They should also have the ability to render HTML into this content.

Likely we want something like:

<div class="heading"> <!-- holds style delivery -->
  <slot name="heading"> <!-- normalize this name to that in other elements -->
    <h2>${this.heading}</h2> <!-- holds default headline level but reverts default heading styles -->
  </slot>
</div>

Or something.

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 actually did not use a slot because of the fact that users have too much flexibility on the heading here and can actually use other things besides heading elements, such as p or div. I wanted to kind of enforce this one to be a heading. I can of course replace it with a slot.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is a really difficult balance to tread. We've been asked in the past by the accessibility team to ensure that patterns like this can accept multiple levels of heading to ensure the content is accessible, even if we haven't always gotten back to the related fixes 🙈. If there were other practical approaches to ensuring default delivery AND supporting varying levels of headlines, any new insight into the conversation that you might have would be greatly appreciated.

strictness vs support vs flexibility 😓

Copy link
Contributor Author

@Rocss Rocss Apr 23, 2024

Choose a reason for hiding this comment

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

Added a heading slot in the end.
Can we throw a warning if the slotted element is not a heading element (not h1,2,3... or role="heading")?

LE: well actually you can add nested slotted element which has a heading inside....

Copy link
Contributor

Choose a reason for hiding this comment

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

I kind of like that as an option, though the work to do so is non-trivial. Might be worth creating an issue to come back to that at a later date?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, I'll create an issue for this. Do you see this being useful for other components as well, such as Dialogs?

Copy link
Contributor

Choose a reason for hiding this comment

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

Rather than a dev mode warning I would like to get it surfaced up to the documentation site to have more visibility

packages/contextual-help/src/ContextualHelp.ts Outdated Show resolved Hide resolved
packages/contextual-help/src/ContextualHelp.ts Outdated Show resolved Hide resolved
packages/contextual-help/src/ContextualHelp.ts Outdated Show resolved Hide resolved
packages/contextual-help/src/ContextualHelp.ts Outdated Show resolved Hide resolved
packages/contextual-help/src/contextual-help.css Outdated Show resolved Hide resolved
packages/contextual-help/src/spectrum-contextual-help.css Outdated Show resolved Hide resolved
></sp-icon-info-outline>
`}
</sp-action-button>
<sp-overlay
Copy link
Contributor

Choose a reason for hiding this comment

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

We may also want to look at the trigger directive here, as it lists as slightly more performant that leveraging the element.

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 not aware of this directive. I think it is really cool that is handles the slottable-request event for you.
A thing I did not found straight-forward is the open/close events. Is there a better way to know when it opens/closes events besides adding event listeners on the ContextualHelp class?
I'd need to know of open/close states for the button's active state. Would you consider a good addition to add active attribute on the trigger as a built-in feature of the trigger directive?

Copy link
Contributor

@Westbrook Westbrook Apr 23, 2024

Choose a reason for hiding this comment

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

It's not even "brand new" quite yet, as we're working through its specifics internally and with some select early clients before we mark it as "for consumption". Some approach to this seems like an important part of this API, but I'm not sure direct manual handling of specific attributes inside of the directive is the right thing to do here.

While not pretty, that best I can think of with the established API is to use specific handing of slottable-request to toggle open which is rendered to active. In API extensions, I'd love to chat more on the possibilities around:

  • adding handleOpen/handleClose callbacks to the options bag
  • advanced used of the trigger directive as a TriggerController that held the open state for you to be able to render with (feels either really smart of trying too hard)
  • other (better) things...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As a consumer, the first thing I looked for was a handleOpen and handleClose callback, as slottable-request event is part of the internal works of this directive and I don't know if as a consumer I should be aware of that.

sp-open/sp-close events are fine, but are actually a bit delayed, because of the CSS transitions that have dispatched I guess. So the question with handleOpen / handleClose would be if the timing of calling these callbacks should be on the handleSlottableRequest method, or a bit late, on sp-open and sp-closed.

In my case as you mentioned sp-open/sp-close are a bit late :(

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, sp-open and sp-close are not "correct for this situation.

If we went with callbacks, they would likely happen at slottable-request time, because that represents the outside of the open/close transition, rather than only the end of each transition. But, it could be argued that this belongs at the beginning of each transition, which is when the state actually changes. 🤔

Relying on the state feels nicer than relying on a knowable part of the lifecycle, which is why I like the TriggerController, but there is much to think about here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

that best I can think of with the established API is to use specific handing of slottable-request to toggle open which is rendered to active.

Regarding this, I don't think this works, as the event is attached on the sp-overlay, which I don't have access to.

Copy link
Contributor

Choose a reason for hiding this comment

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

Indeed. So we can ship once and edit later leveraging <sp-overlay> directly, or we can hold this for an expansion of the directives capabilities. Do you have a preference on that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Depending on when exactly would the directive be expanded. If it's more than 1-2 releases, then I'd ship it as it is and come back when this behaviour is available.

@sp-closed=${() => {
this.overlayOpen = false;
}}
@slottable-request=${this.isMobile.matches
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you want to also offer the option for a consumer to lazily render the content of this overlay?

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 does not seem like the kind of component you interact with way too many times, as its content does not change often.
So I am thinking it would be a good practice to lazy load its content. On the other hand, its content is indeed modest. What is your opinion on this?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we'd want it at some point. It is a performance optimization, so I'm OK with excluding it for the initial release, but prefer to take your lead as you're the one actually doing the work.

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'd ship it as it is for a component which theoretically should have just some text inside.

@Rocss Rocss requested a review from a team May 16, 2024 13:56
@Rocss
Copy link
Contributor Author

Rocss commented May 16, 2024

@Rajdeepc as per office hours discussion, I removed the trigger directive usage and went back to sp-overlay, as it was better suited for my component.

@TarunAdobe
Copy link
Contributor

Can you look into why these examples don't work for this component?
image

@Rocss
Copy link
Contributor Author

Rocss commented May 21, 2024

Can you look into why these examples don't work for this component? image

@TarunAdobe seems to be due to the type of the controls: radio, number, and text which do not map well on Picker. I can convert the radio one into select, but the number and text I don't think that those can be converted. Do we have a way to exclude them from the docs, but not the storybook?

@TarunAdobe
Copy link
Contributor

@Rocss Hmm seems like you're right! Thanks for pointing it out. We will take this up in a separate PR as this needs some work around how we create these demos.

`}
</sp-action-button>
<sp-overlay
trigger="trigger@click"
Copy link
Contributor

Choose a reason for hiding this comment

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

@Rocss Updates on this? Do you think using DependencyManagerController here would benefit the component?

Comment on lines +66 to +67
await nextFrame();
await nextFrame();
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need to wait for a few frames here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Waiting for DOM clean up to complete, similar to here. The test fails without it because it still finds the popover in the DOM.

@Rajdeepc
Copy link
Contributor

@Rocss Would it be okay to surface up a contextual-help-memory.test.ts with this PR so that we can triage any memory leaks in the code similar to this

@Rajdeepc
Copy link
Contributor

@Rocss Hmm seems like you're right! Thanks for pointing it out. We will take this up in a separate PR as this needs some work around how we create these demos.

Should be fixed by #4512

@blunteshwar
Copy link
Contributor

Looks like vrts's are failing!

@Rocss
Copy link
Contributor Author

Rocss commented May 29, 2024

@blunteshwar I observe this, however, the failing tests are not related to this PR, and the error seems to be for Action Button Error: There was no baseline image to compare against.. Is this happening on any other PR?

Copy link
Contributor

@TarunAdobe TarunAdobe left a comment

Choose a reason for hiding this comment

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

LGTM!!! We will work on adding a dependency manager (if feasible and required) in a separate PR.

Copy link
Contributor

@Rajdeepc Rajdeepc left a comment

Choose a reason for hiding this comment

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

Thanks for bringing this in!

@Rajdeepc Rajdeepc merged commit a259aa3 into main Jun 3, 2024
64 checks passed
@Rajdeepc Rajdeepc deleted the contextual-help branch June 3, 2024 10:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants