Skip to content

fix: show a disabled option's reason when its row is hovered - #123

Merged
agatha197 merged 3 commits into
mainfrom
fix/gh-122-show-a-disabled-option-s-reaso
Oct 30, 2026
Merged

agatha197 merged 3 commits into
mainfrom
fix/gh-122-show-a-disabled-option-s-reaso

Conversation

@lablup-octodog

@lablup-octodog lablup-octodog commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Resolves #122

Summary

  • A disabled option with a reason now shows it in a tooltip when the pointer is anywhere on the row. This covers Selector, MultiSelector and PagedSelector, which share OptionDisabledReason.
  • The glyph at the end of the row is removed, with the wrappers that only placed it. A row with a reason now looks the same as a silently disabled row until it is hovered, and it lays out like any other row.
  • The reason stays in the option's accessible name as VisuallyHidden text.
  • The tooltip is attached to the row. The row element belongs to Astryx in two of the three selectors and renderOption only reaches its content, so the row is found from the hidden text with closest(). That way the listener also covers the row padding and the check mark area, which a wrapper inside renderOption would miss.
  • The tooltip uses Astryx's default placement, above the row and centred. It therefore covers part of the option above while it is open.
  • touchTrigger="tap" is set because Astryx treats role="option" as an action and would otherwise keep the tooltip shut on a tap.
  • Removed the pointer-events: auto rule and its comment: Astryx 0.7.3 sets no pointer-events on a disabled row. Confirmed in Chromium, see the test plan.

Why

In backend.ai-webui, a user who hovers a disabled select option sees no explanation unless they find the small glyph at the end of the row. backend.ai-webui picks this change up with the next @lablup/ui-common release.

Test plan

  • Tests in src/formControls/optionDisabledReason.test.tsx (Selector, MultiSelector) and src/components/PagedSelector/PagedSelector.test.tsx: hovering the row opens the tooltip, and in the former leaving the row closes it. The reason is in the row as hidden text, no glyph is drawn, and a bare disabled: true row has no tooltip.
  • Stories: Form Controls/Selector and Form Controls/MultiSelector → DisabledOptionReason, and Components/PagedSelector → Default (Item 017).
  • Checked in headless Chromium with the final code, on the Selector story only: hovering the row opens the tooltip above it, on one readable line at 1280px and at a 300px viewport, and the row reads as option "South No agent in this region has a GPU." in the accessibility tree. MultiSelector and PagedSelector were checked in a browser earlier, with the glyph and the tooltip beside the panel; with the final code they are covered by the tests.

Not checked in a browser; please try these by hand:

  • The row padding and the check mark area. Those checks hovered the row's centre only. Coverage of the edges rests on the listener being on the row element.
  • Touch, including a swipe that starts on a row with a reason, and the bottom sheet presentation.
  • The first row of a list, and moving the pointer up from a row with a reason to the option above it.

astryx/components/Selector.doc.mjs and MultiSelector.doc.mjs were edited to match the new note in scripts/gen-wrapper-docs.mjs rather than regenerated, because the script could not be run in this environment. The staleness test in src/astryxIntegration.test.ts passes.

Verification

Output of pnpm run verify (last lines):

$ node scripts/check-pack.mjs
Packed artifact clean: @lablup/ui-common 1185 file(s), 169 export path(s) resolve; @lablup/ui-common-cli 52 file(s), bin and imports resolve.
$ node scripts/check-integration.mjs && astryx integration verify
check:integration: @lablup/ui-common@0.2.0-alpha.20 validates with 0 errors, 0 warnings (72 docs type-checked)
Integration package ready

[ok] @lablup/ui-common@0.2.0-alpha.20

1185 packed files; 144/144 required files present.

The reason opened only with the pointer on the small glyph at the end of the row. The row itself never blocked hover, as the glyph's pointer-events rule assumed: Astryx 0.7.3 sets no pointer-events on a disabled row. The tooltip now hangs on the row, found from the glyph because the selectors own that element, and sits beside it so it covers no other option. The glyph stays as the visible mark and keeps the reason as its accessible name.
@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR

GitHub Pages may take up to a minute to hydrate after the deploy.

🧩 Changed Components

Component Changed Stories Open
PagedSelector source 7 Storybook ↗
6 other changed file(s) in src/
  • src/formControls/MultiSelector/MultiSelector.stories.tsx
  • src/formControls/MultiSelector/MultiSelector.tsx
  • src/formControls/Selector/Selector.stories.tsx
  • src/formControls/Selector/Selector.tsx
  • src/formControls/optionDisabledReason.css
  • src/formControls/optionDisabledReason.tsx

📦 Bundle Size

Group Gzip Δ Gzip vs base
assets 15.7 kB −0.1 kB
formControls 15.3 kB +0.0 kB
components/PagedSelector 4.9 kB +0.0 kB

Total gzip (JS + CSS): 201.3 kB (−0.1 kB vs origin/main)


Generated by the PR Preview workflow for 007677a · Storybook · CI run

@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Preview published under the pr-123 dist-tag (npmjs): 0.2.0-alpha.20.pr-123-20261030092531-007677ae1

pnpm add @lablup/ui-common@0.2.0-alpha.20.pr-123-20261030092531-007677ae1
pnpm add -D @lablup/ui-common-cli@0.2.0-alpha.20.pr-123-20261030092531-007677ae1

In backend.ai-webui: pnpm run ui-common:pin pr-123. A consumer PR pinned to a preview cannot merge; repin to canary after this PR merges.

@lablup-octodog

Copy link
Copy Markdown
Contributor Author

Agent review — round 1 at c3201ee

1 finding, 0 blocking. Tier: Medium, worked out from the changed paths (no High or all-Low match, no REVIEW.md).

# Tag File:line Finding Verdict Bucket Outcome
O1 Nit src/formControls/optionDisabledReason.tsx:50 With touchTrigger="tap" on the row, a swipe that starts on a row with a reason also opens the tooltip. Astryx's useTouchTrigger shows it on pointerdown and does not handle pointercancel, so it stays open after the scroll until the next tap. PLAUSIBLE (read from source, not run on a device) C not-worth

O1 is not a blocker: the cost is a stray tooltip that one tap closes, and the PR deliberately keeps tap access to the reason. The whole row is a much larger target than the old glyph, so please include a swipe in the touch check the PR already asks for by hand.

What was checked

  • The row lookup and the tooltip attachment. rowRef is set before Tooltip's layout effect runs, because the glyph comes first in the tree, and re-renders leave it attached. A tooltip inside its own anchor is a pattern Astryx already supports.
  • pointer-events: none is set on a disabled row in Selector, MultiSelector, PagedSelector or ui-common's stylesheets, so removing the old rule is safe.
  • touchTrigger="tap": Astryx's isActionTrigger lists option, as the comment says. The role="row" case would have opened on a tap anyway.
  • The structure and class changes around .uic-option-disabled-reason: nothing in backend.ai-webui selects on that class or on .uic-icon-with-tooltip.
  • Docs, stories, the changelog and gen-wrapper-docs.mjs match the new behaviour.
  • Targeted tests: optionDisabledReason.test.tsx and PagedSelector.test.tsx, 71 passed.

Not covered

  • No fixes landed after this review, so there is nothing unreviewed at the head.
  • No browser or device check in this review. The role="row" lookup (MultiSelector once an option has an action) has no test; it was checked by reading Astryx's row markup only.
  • The by-hand checks listed in the PR's test plan are still open: row padding and check mark area, touch and bottom sheet, narrow viewports.

@lablup-octodog
lablup-octodog marked this pull request as ready for review October 30, 2026 08:23
The row hover now carries the reason, so the glyph at the row's end is gone in Selector, MultiSelector and PagedSelector, with the wrappers that only placed it. The reason stays in the option's accessible name as visually hidden text.
github-actions Bot added a commit that referenced this pull request Oct 30, 2026
The reason's tooltip takes Astryx's default placement, above the row, instead of the end. It no longer shrinks into the width left beside the panel.
github-actions Bot added a commit that referenced this pull request Oct 30, 2026
@agatha197
agatha197 merged commit ad744b1 into main Oct 30, 2026
10 checks passed

This branch was successfully deployed

1 active deployment
release — 007677ae Deployed Oct 30, 2026 by lablup-octodog via npmjs #120
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.

Show a disabled option's reason on row hover instead of on a glyph

2 participants