Add reusable CheckboxListFilter with overflow-triggered sticky search - #253
Merged
Conversation
FilterPanel's checkbox/radio option list was a one-off inline renderer whose inline search box only ever appeared when a filter explicitly opted in via `searchable: true` - so a long, unsearched list scrolled past dozens of rows with no way to narrow it. Extract that renderer into a standalone, exported CheckboxListFilter (Filter/CheckboxListFilter.tsx) so applications can reuse the same checkbox/radio picker outside a FilterPanel, following the pattern proven by Stagehand's bespoke CheckboxPicker escape hatch. The list is now bounded to a fixed, scrollable box (.pv-option-list), and `searchable` becomes a tri-state: `true`/`false` keep forcing the search box on or off exactly as before, while the new default (`undefined`) shows it only when the option list actually overflows its box - measured via useOptionListOverflow against an off-screen mirror of every option, so a live search filtering the visible rows never itself shrinks the measured content and un-decides that the box needed a search box in the first place. The search box is pinned to the top of the list's own scroll container via CSS position: sticky. FilterPanel's OptionList is now a thin adapter over CheckboxListFilter, keeping FilterPanelProps and FilterDefinition unchanged for existing consumers such as Chronicle Workbench.
Covers the pure overflow decision (optionListOverflows) on plain numbers, plus CheckboxListFilter itself: no search box for a list that fits, a sticky search box pinned to the top of the box once the list overflows, search/false/true forcing that decision explicitly, label filtering (case-insensitive, no-matches message), and checkbox/radio selection and toggling. The DOM-based specs stub ResizeObserver, Element.scrollHeight, and getComputedStyle(...).maxHeight the same way other suites in this package work around jsdom's missing layout engine, letting a spec dictate whether the option list "overflows" without a real browser.
CheckboxListFilter.stories.tsx demonstrates the standalone component: a short list with no search box, a 30-option list whose search box grows out of the overflow and filters/selects correctly, and both explicit searchable overrides. Two new FilterPanel stories show the same behaviour through the full anchored panel - a 30-repository filter that grows its own search box next to a 3-option filter that never does.
CheckboxListFilter.stories.tsx plus two new stories on FilterPanel bring the totals from 67/277/67 to 68/283/68 (modules/stories/docs pages). While updating the ratchet, also fixed the adapter and matrix log lines: they printed literal "277"/"67" text instead of the computed counts, so they were already silently stale before this change - now they read from the same variables the check enforces.
The off-screen mirror list used to decide whether a search box is needed duplicated each option's real label/count as literal DOM text, so a search that filters the real list down still leaves the mirror's matching text discoverable by any text-content query (e.g. Testing Library's getByText/queryByText, which do not consider aria-hidden). CSS generated content occupies the same layout space for measurement purposes without ever becoming DOM text, so the mirror can no longer be mistaken for a real, currently-visible row.
Five options is enough for Department's own option list to overflow its fixed-height box, so it now legitimately grows a search box of its own - inheriting this panel's placeholder text by design (see for_FilterPanel/when_a_filter_group_has_no_own_search_placeholder.tsx). The story's play function queried by that placeholder text globally and started matching both boxes. Scope to .pv-search, the panel's own top-level search container, rather than either per-group one.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Consolidates two duplicate checkbox-list filter implementations (Chronicle's own
FilterPaneloption list and Stagehand's bespokeCheckboxPicker) into one reusable renderer, per Cratis/Chronicle#3991.Added
CheckboxListFilter, a reusable checkbox/radio picker with a search box that becomes sticky and only shows once the option list overflows its bounded height (Reuse filter type Chronicle#3991)Changed
FilterPanel's internal option-list renderer now delegates toCheckboxListFilter, gaining a scroll-capped list and overflow-triggered sticky search; the publicFilterPanelProps/FilterDefinitionAPI is unchanged and fully backward compatible (Reuse filter type Chronicle#3991)