Repository navigation
feat(lab): MobilePowerSearch edits list values through MobileTokenizer - #7979
Merged
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
AI review status for this pull request.
|
Contributor
PR Analysis Report📚 Storybook Preview🧪 Sandbox PreviewModified ComponentsMobilePowerSearch (@astryxdesign/lab) · View in Storybook
MobileTokenizer (@astryxdesign/lab) · View in Storybook
Bundle Size Summary
Accessibility AuditStatus: No accessibility violations detected. Generated by PR Enrichment workflow | Storybook | Sandbox | View full report |
imdreamrunner
force-pushed
the
feat/lab-mobile-powersearch-mobile-tokenizer
branch
from
October 23, 2026 18:24
5b6b4a2 to
a6660f7
Compare
imdreamrunner
force-pushed
the
fix/lab-mobile-powersearch-tests-per-step-dialogs
branch
from
October 23, 2026 18:24
058af0f to
22aa5bd
Compare
imdreamrunner
changed the base branch from
fix/lab-mobile-powersearch-tests-per-step-dialogs
to
main
October 23, 2026 18:47
imdreamrunner
force-pushed
the
feat/lab-mobile-powersearch-mobile-tokenizer
branch
from
October 23, 2026 18:47
a6660f7 to
fb9240d
Compare
3 tasks done
imdreamrunner
force-pushed
the
feat/lab-mobile-powersearch-mobile-tokenizer
branch
from
October 23, 2026 19:08
fb9240d to
4f86a26
Compare
The value step for a string_list or entity_list field rendered Core Tokenizer, a desktop chip input with a popover menu, inside the sheet. It now renders the Lab MobileTokenizer: the trigger shows the staged tokens in the step, and tapping it opens a tall searchable sheet over the step, titled with the field's name. Search source, free-text creation, debounce, menu size, disabled state, value mapping and staging are unchanged; the step's footer still commits the value. MobileTokenizer gains two optional props that mirror Core Tokenizer: `isLabelHidden`, forwarded to Field so the step's heading and operator rows are not repeated (the trigger and the sheet keep the label as their accessible name), and `renderItem`, which renders a result row's content beside its checkbox so an entity field's custom rows carry over. The MobilePowerSearch test helpers now read the flow's active step as the first open dialog that is not hidden: since each step owns its dialog, the outgoing step stays open, inert and hidden through a fade jsdom never fires, and the old first-open-dialog read landed on it.
imdreamrunner
force-pushed
the
feat/lab-mobile-powersearch-mobile-tokenizer
branch
from
October 23, 2026 19:08
4f86a26 to
f87a0af
Compare
imdreamrunner
deleted the
feat/lab-mobile-powersearch-mobile-tokenizer
branch
October 23, 2026 19:25
3 tasks done
This branch was successfully deployed
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.
feat(lab): MobilePowerSearch edits list values through MobileTokenizer
User need
Someone filtering on a touch layout picks the people or values of an
entity_listorstring_listfield inside the MobilePowerSearch value step. That step rendered CoreTokenizer: a desktop chip input whose suggestions open in a popover menu, inside a sheet the user is already standing in. On a phone the popover is a second overlay competing with the keyboard and the sheet's own scroll, and its chips and menu rows are sized for a pointer. The Lab already has the touch answer,MobileTokenizer: a trigger that shows the chosen tokens and a tall searchable sheet with full-row checkboxes. The owner's ask on the merged prototype was to use it here.Problem and solution fit
MobilePowerSearchValueEditor.tsx,string_listandentity_list: CoreTokenizer→ LabMobileTokenizer(lab-to-lab import, asComments/CommentComposer.tsximports../EmojiPicker). Every behaviour carries over unchanged:searchSource(orEMPTY_SOURCE),hasCreateforstring_list(isArbitraryStringAllowed || !searchSource),debounceMs,maxMenuItems,isDisabled, the value mapping and staging; the step's footer still commits the staged value.MobilePowerSearchValueEditorgains an optionallabel;MobilePowerSearch.tsxpassesdraftField.label, and the tokenizer'slabeluses it, so the inner sheet reads "Assignee". Fallbacks keep the former "Values" / "Entities".MobileTokenizergainsisLabelHidden?: boolean, forwarded toField'sisLabelHidden(the same prop CoreTokenizerhas); the trigger keepslabelas its accessible name, and so does the sheet.renderItemkept. CoreTokenizer'srenderItem?: (item: T) => ReactNodeis a plain content renderer that Core shows beside its check icon. The same signature fitsMobileTokenizer's row — content beside theCheckboxIndicator— so it is added with that signature, andentity_listkeeps passingoperatorValue.renderItem.MobileTokenizeredits are additive optional props only (open feat(core): BottomSheet stacks by open order, replaces on a same-update switch, and BottomSheetSwitcher is deprecated #7648 edits the same file; a separate port of MobileTokenizer into Core Tokenizer is in flight), no restructuring.@inputlist, rationale paragraph),MobilePowerSearch.doc.mjs's Value sheet anatomy, andMobileTokenizer.doc.mjs's props are updated. The stories did not describe the Tokenizer.Current specification
No
currentrecord governs@astryxdesign/lab's MobilePowerSearch or MobileTokenizer; both are Lab prototypes outside the stable compatibility promise (spec:AST-017FR27). The sheets they compose are governed bycomponent:BottomSheetandcomponent:BottomSheetSwitcher(current): a step owns its native modal dialog (DEC-1), so a MobileTokenizer sheet opened from a step is a second modal dialog in the top layer, above the step and under the same mechanism as any other nested dialog. Sheet stacking as a product surface is the open #7648; this PR does not depend on it.Public delta and caller burden
@astryxdesign/labisprivate: true; nothing ships to consumers, andcheck:changesetsplus the changeset coverage classifier agree no Changeset is needed.MobileTokenizer:+ isLabelHidden?: boolean(defaultfalse),+ renderItem?: (item: T) => ReactNode(default: the item label). Both optional; omitted, nothing changes.MobilePowerSearchValueEditor:+ label?: string. Omitted, the former "Values"/"Entities" titles apply.MobilePowerSearch: no prop change. In the value step of a list field, the chip input is replaced by the MobileTokenizer trigger; tapping it opens a second, tall sheet over the step. That second sheet is the intended outcome.button[aria-haspopup="dialog"]named after the field; the inner sheet's dialog is named after the field; the step behind it is not reachable while it is open (top-layer modality); Escape closes only the inner sheet and returns focus to the trigger.Design and alternatives
renderItem— not needed: the signature matches and the row has a natural content slot.Tokenizer'sisLabelHidden, which the in-flight port can carry straight across.Evidence
Unit (jsdom),
MobilePowerSearch.test.tsx, 81 passed. Rewritten for the new flow: "string_list: the mobile tokenizer creates free-text values in its own sheet, staged on the trigger and committed by the footer" (tap the trigger, type in the inner search, tapAdd ABC-1, see the token on the trigger, Done, Add filter →{type: 'string_list', value: ['ABC-1']}) and "entity_list: … picks entities from the search source …" (type "Ada", tap the "Ada Lovelace" checkbox row, Done, Add filter →[{id: 'p1', label: 'Ada Lovelace'}]). New: the inner sheet is named "Assignee" and the step paints no "Entities" text while the trigger is still named "Assignee"; Escape in the inner sheet flips the trigger'saria-expandedto false and closes its dialog while the flow stays open with the trigger still in the step.MobileTokenizer.test.tsx, 10 passed, new: withisLabelHiddenthe Field's label is clipped out of the layout (sr-only) while the trigger and the sheet keep "Tags" as their name, andrenderItemcontent renders inside the checkbox row.Chromium 141 (Playwright 1.56, 390×844 touch),
Lab/MobilePowerSearch→ Touch flow, "Assignee" (entity_list):dialog[open], both:modal; the inner one is named "Assignee";elementFromPointat the viewport centre lands in itinertattribute itself is not set — it is the browser's)button[Assignee]in the step, after Escape and after Donebody overflow: hiddenandscrollYstays 0 through step → inner sheet → back to step; released after the flow closes (scrollY600 on the same wheel)assignee any_of [user-1, user-3](the story's JSON readout)::backdrops at 0.5 alpha stack to ~0.75 dim while the inner sheet is open. Expected until sheet stacking (#7648) lands; reported here, not hiddenScript and log:
mps-tokenizer.mjs,evidence-chromium.md,shot-chromium-final.png(kept with the PR author).WebKit: not run. Headless Playwright cannot launch on the Mac (Mach-port permission), Playwright's WebKit build does not run on the CentOS 9 dev host (missing ICU 66 / woff2 shared libraries, no Ubuntu container image reachable), and real Safari through
safaridriverneedssafaridriver --enable(an admin password / Develop ▸ Allow Remote Automation) which was off on the Mac. A ready script is at~/safari-check/safari/mps-safari.mjs(same checks, W3C WebDriver); enabling safaridriver and running it is a one-command follow-up. The mechanism exercised here — a modal dialog in the top layer over a step dialog, Escape through the shared layer stack, flow-level scroll lock — is the one #7757 verified in WebKit for a CoreDialogopened from a step.Scope
Testing