feat(PowerSearchMobile): the touch form of PowerSearch - #5314
feat(PowerSearchMobile): the touch form of PowerSearch#5314imdreamrunner wants to merge 1 commit into
Conversation
PowerSearch's desktop shape does not survive a phone: the typeahead drops a popover that fights the on-screen keyboard, and the edit popover lays field / operator / value out in a row that has nowhere to go at 390px. PowerSearchMobile keeps the props, the filter model and the tokens, and moves the building into a pinned-tall bottom sheet that drills down field -> operator -> value: - the tap target is the same input shell, showing the filters as tokens; tapping one reopens its editor, where Delete removes it - the field list is grouped, and past seven fields gains a search box pinned under the sheet title - an operator is a drill-down row, shown only when the field defines more than one; with one, the header carries it, so the happy path is two taps - enum commits on a single tap (Selector's mobile pattern), enum_list applies from a pinned footer (MultiSelector's), an empty operator lands with no value step at all, and every other type falls through to the shared value editor - nested filter groups have no touch editor yet: those fields are left out of the list and a dev warning says so Follows the mobile exploration at facebook.github.io/astryx/sandbox/pages/mobile-prototypes/?p=powersearch
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR Analysis Report📚 Storybook PreviewView Storybook for this PR 🧪 Sandbox PreviewView Sandbox for this PR Modified ComponentsPowerSearch (@astryxdesign/core) · View in Storybook
Bundle Size Summary
Accessibility AuditStatus: 1 accessibility violation(s) found — 1 serious. PowerSearch - 1 issue(s)
Generated by PR Enrichment workflow | Storybook | Sandbox | View full report |
cixzhang
left a comment
There was a problem hiding this comment.
Thanks — the sheet is lovely and two taps is the right target.
The hard part is who owns the switch. DateInput settles it inside the component on (pointer: coarse), no width bound; your #5315 does the same for Tokenizer. Here the call site owns it, and the docs teach a width:
const isTouch = useMediaQuery('(max-width: 768px)');
const Search = isTouch ? PowerSearchMobile : PowerSearch;That swaps component identity, so a rotation mid-filter unmounts the half-built filter.
Ideally one PowerSearch picks its own surface. The argument the other way is bundle — PowerSearch doesn't pull BottomSheet today. Comment only because it's a draft; undrafting wants this settled.
Is the tree-shaking worth the call site owning the breakpoint?
[Reviewed by Robohands]
| examples: [ | ||
| { | ||
| label: 'Responsive: one call site, both variants', | ||
| code: `const isTouch = useMediaQuery('(max-width: 768px)'); |
There was a problem hiding this comment.
Hmm, 768 is an iPhone in landscape. Swaps the component mid-filter
| return resultCount; | ||
| }, [resultCount, t]); | ||
|
|
||
| const announce = useAnnounce(); |
There was a problem hiding this comment.
Some of this seems copied from PowerSearch. Probably can share it rather than keep two
| * shows the operator as a row that drills into its own list. Tapping a token | ||
| * reopens that filter's editor, where Delete removes it. | ||
| */ | ||
| export function PowerSearchMobile({ |
There was a problem hiding this comment.
These four typecheck but never arrive. Might need a dev warning at least
|
One more thing worth settling before this undrafts: DateInput keeps [Reviewed by Robohands] |
What
PowerSearchMobile— the touch form ofPowerSearch, in core.Following the mobile exploration: Mobile Prototypes → PowerSearch ("bottom sheet, pinned tall").
Why
PowerSearch's desktop shape doesn't survive a phone. The typeahead drops a popover that fights the on-screen keyboard, and the edit popover lays field / operator / value out in a row that has nowhere to go at 390px.
How
Same props, same
PowerSearchFiltermodel, same tokens. The typeahead dropdown and the row-shaped popover are replaced by a pinned-tall bottom sheet that drills down field → operator → value. Pick between the two variants on viewport and the call site does not change:field.group, each row captioned with the operator it will produce. Past seven fields it gains a search box pinned under the sheet title.enumcommits on a single tap (Selector's mobile pattern);enum_listapplies from a pinned footer (MultiSelector's); anemptyoperator lands with no value step at all; every other type falls through to the sharedPowerSearchValueEditor.Both sheets are
height="tall": the field list resizes as it is searched and the editor's content changes with the operator, so a self-sizing sheet would jump on every keystroke and every step — and tall is the only height that gives mobile-keyboard accommodation, which the text and number editors need. The editor sheet ispurpose="form", so a stray scrim tap can't discard a half-built filter.nestedfilter groups have no touch editor yet. Fields whose only operators are nested are left out of the list and a dev warning says so, rather than opening a blank sheet.Accessibility
<label>pointed at the button would replace its visible text as the accessible name (WCAG 2.5.3). The button is named by its own text, and carriesaria-haspopup="dialog"+aria-expanded.disabledMessagekeeps the target focusable viaaria-disabledand describes it, so the reason is reachable by keyboard; the action stays blocked.Screenshots
Light and dark, iPhone 15: assets/pr-5314
Dark
Test plan
PowerSearchMobile.test.tsx, covering the whole flow: field → operator → value, the enum single-tap commit, the multi-select apply, the empty-operator shortcut, edit/delete, clear-all keeping read-only filters, read-only and disabled, the field search and its empty state, the nested-field warning, and the imperative handle.dist: the flow works end to end with no console errors, the tablet sheet caps at 640px, and the read-only / disabled / error states behave.pnpm lint:strict,pnpm build,pnpm test(7527 core+lab, 2804 cli+apps),typecheck+typecheck:docsacross core/lab/charts/cli/storybook,pnpm -F @astryxdesign/storybook build,pnpm lab:readiness:check— all green.Notes for reviewers
hasAutoFocus,menuWidth,maxOperatorMenuItems,tokenOverflowBehavior— documented on the prop table rather than removed, so one call site can feed both variants.handleRef'sfocusTypeahead()/blurTypeahead()move focus to and from the tap target; there is no typeahead input on this variant.CheckboxListalready uses to send a long list toMultiSelector.