feat: DH-19683: Multi-select combobox component#2671
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #2671 +/- ##
==========================================
+ Coverage 49.76% 50.50% +0.74%
==========================================
Files 774 787 +13
Lines 43945 44782 +837
Branches 11330 11587 +257
==========================================
+ Hits 21871 22619 +748
- Misses 22027 22117 +90
+ Partials 47 46 -1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds a new table-backed multi-select combobox for Deephaven’s Spectrum-based UI stack, introducing a reusable @deephaven/components MultiSelect (and normalized variant) plus a @deephaven/jsapi-components wrapper that binds it to DH tables/viewporting and server-side search.
Changes:
- Introduces
MultiSelect/MultiSelectNormalizedcomponents (tags + inline search + multi-selection ListBox) with supporting hooks/utilities, styles, and tests. - Adds
useMultiPickerProps+jsapi-componentsMultiSelectwrapper to drive the component from a DH table with viewporting + search + label caching. - Updates multi-selection stringification to preserve selected keys that are filtered out of the current items list.
Reviewed changes
Copilot reviewed 30 out of 30 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/jsapi-components/src/spectrum/utils/useMultiPickerProps.ts | New hook deriving MultiSelect props from a DH table, including snapshot-based label resolution and label caching. |
| packages/jsapi-components/src/spectrum/utils/index.ts | Re-exports the new useMultiPickerProps utility. |
| packages/jsapi-components/src/spectrum/MultiSelect.tsx | JSAPI-facing MultiSelect wrapper around MultiSelectNormalized, including open/input search behavior. |
| packages/jsapi-components/src/spectrum/MultiSelect.test.tsx | Unit tests validating wrapper behavior for open/close and search text forwarding. |
| packages/jsapi-components/src/spectrum/MultiPickerProps.ts | Defines table-backed prop shape for the JSAPI MultiSelect wrapper. |
| packages/jsapi-components/src/spectrum/index.ts | Exports the new JSAPI MultiSelect and MultiPickerProps. |
| packages/components/src/spectrum/utils/useStringifiedMultiSelection.ts | Preserves selected keys not present in current normalized items (server-side filtering support). |
| packages/components/src/spectrum/multiSelect/useMultiSelectState.ts | New hook managing controlled/uncontrolled multi-selection state and preserving selection across filtering. |
| packages/components/src/spectrum/multiSelect/useMultiSelectState.test.ts | Tests for useMultiSelectState behavior (controlled/uncontrolled, toggle, filtered preservation). |
| packages/components/src/spectrum/multiSelect/useMultiSelectScrollListener.ts | New hook attaching/removing scroll listeners to the popover scroll area. |
| packages/components/src/spectrum/multiSelect/useMultiSelectScrollListener.test.ts | Tests for scroll listener attachment, invocation, and cleanup. |
| packages/components/src/spectrum/multiSelect/useMultiSelectNormalizedProps.tsx | Converts normalized items/sections to JSX children and stringifies multi-selection for Spectrum interop. |
| packages/components/src/spectrum/multiSelect/useMultiSelectLoadingSpinner.ts | Debounced inline loading spinner visibility logic based on loading state + open state + trigger mode. |
| packages/components/src/spectrum/multiSelect/useMultiSelectLoadingSpinner.test.ts | Tests for spinner debounce and visibility behavior across states. |
| packages/components/src/spectrum/multiSelect/useMultiSelectKeyboard.ts | Keyboard handling + virtual focus management for MultiSelect (arrows/enter/escape/backspace, aria-activedescendant). |
| packages/components/src/spectrum/multiSelect/useMultiSelectKeyboard.test.ts | Tests validating keyboard handler behavior. |
| packages/components/src/spectrum/multiSelect/useMultiSelectFilter.ts | New hook managing controlled/uncontrolled search text and client-side filtering (or skipping for server-side). |
| packages/components/src/spectrum/multiSelect/useMultiSelectFilter.test.ts | Tests for filtering behavior and controlled input handling. |
| packages/components/src/spectrum/multiSelect/multiSelectUtils.tsx | Utilities to flatten JSX children, filter entries, and resolve selection to string sets. |
| packages/components/src/spectrum/multiSelect/multiSelectUtils.test.tsx | Tests for the MultiSelect utility functions. |
| packages/components/src/spectrum/multiSelect/MultiSelectTag.tsx | Tag UI subcomponent with remove button for selected items. |
| packages/components/src/spectrum/multiSelect/MultiSelectTag.test.tsx | Tests for tag rendering and remove behavior. |
| packages/components/src/spectrum/multiSelect/MultiSelectProps.ts | Public props for MultiSelect plus MultiSelectNormalizedProps for normalized-item usage. |
| packages/components/src/spectrum/multiSelect/MultiSelectNormalized.tsx | Normalized variant that adapts normalized items/sections into the base MultiSelect. |
| packages/components/src/spectrum/multiSelect/MultiSelectListBox.tsx | Private popover content component rendering either empty state or a Spectrum ListBox. |
| packages/components/src/spectrum/multiSelect/MultiSelect.tsx | Core MultiSelect implementation (Field wrapper, tags + input trigger, popover, selection/filter/keyboard integration). |
| packages/components/src/spectrum/multiSelect/MultiSelect.scss | Styling to match Spectrum ComboBox visuals (trigger, tags, input, focus/invalid/quiet variants). |
| packages/components/src/spectrum/multiSelect/index.ts | Exports MultiSelect modules from the new multiSelect package folder. |
| packages/components/src/spectrum/index.ts | Re-exports multiSelect from the main Spectrum entrypoint. |
| packages/components/package.json | Adds React Spectrum/Aria/Stately + icon dependencies required by MultiSelect. |
Comments suppressed due to low confidence (1)
packages/jsapi-components/src/spectrum/utils/useMultiPickerProps.ts:261
ItemSelectionin this codebase is'all' | Set<ItemKey>, but this effect only handlesArrayand'all'. WhenselectedKeys/defaultSelectedKeysis aSet(the common case),selectedKeySetbecomes an empty Set, so no labels are cached andselectedItemLabelsnever populates. Update this logic to handleSet/iterables (e.g.,currentSelectedKeys instanceof SetorcurrentSelectedKeys != null && currentSelectedKeys !== 'all') and buildselectedKeySetfrom it.
let selectedKeySet: Set<string> | null;
if (currentSelectedKeys instanceof Array) {
selectedKeySet = new Set(currentSelectedKeys.map(String));
} else if (currentSelectedKeys === 'all') {
selectedKeySet = null;
} else {
selectedKeySet = new Set<string>();
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let isCanceled = false; | ||
| hasLoadedSnapshotRef.current = true; | ||
|
|
|
Will be continued in #2685 |
Add multi-select combobox component. Tested with (and required for) deephaven/deephaven-plugins#1347