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 #4108

Closed

Conversation

jcfranco
Copy link
Member

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

@jcfranco jcfranco requested a review from a team as a code owner February 14, 2022 18:12
@github-actions github-actions bot added this to the Sprint 02/14 - 02/25 milestone Feb 14, 2022
@github-actions github-actions bot added the bug Bug reports for broken functionality. Issues should include a reproduction of the bug. label Feb 14, 2022
@jcfranco
Copy link
Member Author

Going to rebase and resubmit once more. This PR has the same issue as #4010 (Screener check not reporting).

@jcfranco jcfranco closed this Feb 14, 2022
@jcfranco jcfranco deleted the jcfranco/2655-apply-consistent-disabled-behavior branch February 15, 2022 04:17
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.

None yet

1 participant