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

fix: ensure components are disabled consistently #4010

Closed

Conversation

jcfranco
Copy link
Member

@jcfranco jcfranco commented Jan 26, 2022

Related Issue: #2655

Summary

This establishes a pattern to handle the disabling of interactive components.

Implementation of interactive components should follow these steps:

  1. Update the component to implement the InteractiveComponent interface.
  2. Use updateHostInteraction (src/utils/interactive.ts) on the component's componentDidRender lifecycle method – this will update tabindex and aria-disabled attributes, accordingly.
  3. Include the disabled mixin from src/assets/styles/includes.scss – this provides the base styles for disabled components.
  4. If the interactive component has a popover/popper element, make sure to close it when the component is disabled and prevent it from being opened programmatically. Note that no utils are available for this, so this will need to be implemented via watchers or so.
  5. Optionally, set disabled on any supporting, internal components (e.g., <calcite-slider> disables internal <button>s).
  6. The component must be tested with the disabled test helper (src/tests/commonTests).

Notes

  • disabled components set tabIndex on the host and assume it will not be modified by end-users - it is set on the host to prevent tabbing into children:

    From WICG/inert#48:

    From step 3 of https://w3c.github.io/webcomponents/spec/shadow/#sequential-focus-navigation

    [...] an element whose tabindex value is negative must not be appended to NAVIGATION-ORDER.

    Which in other words means that if an element has tabindex=-1 and a shadowRoot, the focus won't be able to reach the element's contents (distributed or not) 🎉

  • disabling a component with an active popover will close it and prevent programmatically opening it

    • reason 1: disabled popovers may end up covering surrounding interactive elements
    • reason 2: setting opacity on the popovers root will create a stacking context that the popover will not be able to escape in a straightforward manner
  • calcite-label's disabled property is deprecated

  • tweaked styles and rendering of calcite-input-date-picker to avoid pointer-events overrides.

  • programmatically disabling a component that owns focus will not affect the focus order. For example, if the color picker's hex input is focused and some extraneous code disables the color picker, a user would still be able to tab within the the color picker's focusable controls. I think this won't be feasible in a performant way until inert is implemented across browsers. FWIW, I don't think this will be an issue for most use cases, but we'll have to see. As a workaround, endusers could focus another element when disabling a focus-owning component.

  • Some components emit one or more click events from implementation, I'll create a separate issue for this.

  • Disabled components get their HTMLElement#click() hijacked to prevent programmatic clicking.

The following components were updated to follow the same disabled behavior:

  • calcite-action.tsx
  • calcite-block.tsx
  • calcite-button.tsx
  • calcite-checkbox.tsx
  • calcite-color-picker.tsx
  • calcite-combobox-item.tsx
  • calcite-combobox.tsx
  • calcite-date-picker-day.tsx
  • calcite-dropdown.tsx
  • calcite-fab.tsx
  • calcite-filter.tsx
  • calcite-inline-editable.tsx
  • calcite-input-date-picker.tsx
  • calcite-input-time-picker.tsx
  • calcite-input.tsx
  • calcite-link.tsx
  • calcite-list-item.tsx
  • calcite-list.tsx
  • calcite-panel.tsx
  • calcite-pick-list.tsx
  • calcite-radio-button.tsx
  • calcite-radio-group.tsx
  • calcite-rating.tsx
  • calcite-select.tsx
  • calcite-slider.tsx
  • calcite-sortable-list.tsx
  • calcite-split-button.tsx
  • calcite-stepper-item.tsx
  • calcite-switch.tsx
  • calcite-tab-title.tsx
  • calcite-tile-select.tsx
  • calcite-tile-select-group.tsx
  • calcite-tile.tsx
  • calcite-value-list.tsx

Pending

  • ✅Wrap up and wire up test helper
  • ✅ Remove remaining obsolete styles (including stacked opacities)
  • ✅ Address and remove remaining TODOS

Questions

  • Does calcite-label need disabled? Is it considered interactive? It only forwards the click on labelable components. – will deprecate as disabled label behavior depends on labelable component
  • Do we need separate utils for interactive components w/ popovers? – possibly, but will wait until floating-ui refactor
  • Do we want calcite-stepper to keep overriding pointer events on items to display the disabled (not-allowed) cursor?
    disabled-stepthe pointer-events override & custom cursor will be removed for consistency

@github-actions github-actions bot added this to the Sprint 01/17 - 01/28 milestone Jan 26, 2022
@github-actions github-actions bot added the bug Bug reports for broken functionality. Issues should include a reproduction of the bug. label Jan 26, 2022
@driskull
Copy link
Member

driskull commented Jan 27, 2022

Does calcite-label need disabled? Is it considered interactive? It only forwards the click on labelable components.

I'm not sure on this one. Its probably easier to tell if a form element is disabled if its label is also grayed out

Do we need separate utils for interactive components w/ popovers?

Possibly. For floating-ui work, I created an interface we could use to help tackle this. We could make a util to help with toggling of disabled.

Do we want calcite-stepper to keep overriding pointer events on items to display the disabled (not-allowed) cursor?

I'm not sure on this one.

src/utils/interactive.ts Outdated Show resolved Hide resolved
@jcfranco
Copy link
Member Author

jcfranco commented Feb 8, 2022

@benelan Can you help me test this out? Some things to look out for:

  • focusing via keyboard/mouse is prevented
  • consistent styling across components and their children
  • opacity should not stack (otherwise it looks too faded)
  • additional components to adopt this pattern (handled in follow-up issue)

@macandcheese can you take a look at the Screener diffs? 👀

@jcfranco jcfranco marked this pull request as ready for review February 8, 2022 00:07
@jcfranco jcfranco requested a review from a team as a code owner February 8, 2022 00:07
@jcfranco
Copy link
Member Author

jcfranco commented Feb 9, 2022

/merge master

@jcfranco
Copy link
Member Author

Closing and reopening to see if it restores the Screener check (it's currently not picking up the latest changes).

@jcfranco jcfranco closed this Feb 14, 2022
@jcfranco jcfranco reopened this Feb 14, 2022
@jcfranco
Copy link
Member Author

No dice. Gonna resubmit this again.

@jcfranco jcfranco closed this Feb 14, 2022
@jcfranco jcfranco deleted the jcfranco/2655-ensure-consistent-disabled-behavior branch February 14, 2022 18:09
@jcfranco
Copy link
Member Author

jcfranco commented Feb 14, 2022

☝️ #4108

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Bug reports for broken functionality. Issues should include a reproduction of the bug.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants