Skip to content

fix(Tokenizer): hold back the touch sheet presentation until its UX pass finishes - #8735

Merged
imdreamrunner merged 1 commit into
mainfrom
fix/tokenizer-hide-sheet-presentation
Oct 27, 2026
Merged

imdreamrunner merged 1 commit into
mainfrom
fix/tokenizer-hide-sheet-presentation

Conversation

@imdreamrunner

Copy link
Copy Markdown
Contributor

Maintainer impact

Tokenizer's touch sheet presentation (component:Tokenizer DEC-3, FR16–FR24) is on main behind experimental={{presentation}}, and the next release would announce it. Its user experience is still being finished on the Lab components, so a consumer who opts in today gets a surface whose details are about to move. The touch sheet is held back until its UX pass finishes; the implementation stays, unexposed.

Intended invariant

  • spec:AST-017 FR21: an internal entry is undocumented, outside the public API and its compatibility promise, versioned in lockstep with Core.
  • architecture:react-component-runtime INV13: a surface Astryx's own packages need but consumers must not see is reached through @astryxdesign/core/internal/*, a subpath limited by lint (@astryx/no-core-internal-import) to Core and Lab.
  • component:Tokenizer FR1–FR15, AR1–AR5 (the inline combobox) are unchanged: every public Tokenizer renders the popover presentation, as before feat(core): Tokenizer touch sheet behind experimental.presentation #7977.
  • Writing records: docs/contributing/spec-writing.md.

Change

Public API. TokenizerProps no longer has experimental; the public Tokenizer has one signature, TokenizerProps, so ComponentProps<typeof Tokenizer> and every public call name no presentation and keep the released input-only ref. The implementation is untouched: Tokenizer.tsx still reads the presentation options and renders TokenizerBottomSheet (lazy) in the sheet branch.

Internal path: the INV13 ./internal/* entry, not an internal-only prop. @astryxdesign/core/internal/tokenizer-presentation re-exports TokenizerWithPresentation — the same Tokenizer function typed with TokenizerWithPresentationProps (experimental?: {presentation} and ref: Ref<HTMLInputElement | HTMLButtonElement>) — plus the two types, by name. Why this and not a __-prefixed prop on the public type: the repo already has the entry pattern for exactly this case (internal/touch, #8464): the subpath is registered in package.json exports and scripts/sync-exports.js, is undocumented, is outside the compatibility promise, and lint refuses it anywhere but Core and Lab — so the sheet is reachable by MobilePowerSearch (#8001, on hold) and by Core's own tests, and by nothing else. An internal prop omitted from the public type would still ride the public component's props at runtime and would need its own convention; an entry costs one export and a cast, no runtime. The sheet suite (TokenizerBottomSheet.test.tsx, 62 tests), the SSR test and the own-content adopters test now render TokenizerWithPresentation from ../internal/tokenizer-presentation; Tokenizer.props-type.test.tsx proves, with @ts-expect-error, that experimental is not on TokenizerProps nor on the public component, that the public ref stays input-only, and that only TokenizerWithPresentation admits the option and the wider ref. A new internal/tokenizer-presentation.test.ts checks the entry re-exports the one component by name and that the public Tokenizer barrel exports exactly Tokenizer. experimental-isolation (CLI goldens) agrees: nothing public names the sheet.

Docs and stories. Tokenizer.doc.mjs is back to its content before #7977 (the experimental prop entry in the English and Chinese prop tables and the dense summary are gone — that commit was the only change to the file since, so the restore is exact; 16 lines). The three experimental stories (Experimental: bottom sheet, Experimental: adaptive, Experimental: bottom sheet states) leave Tokenizer.stories.tsx (140 lines, likewise the file's only change since). They are not kept under an internal location: Storybook has none — every stories/**/*.stories.* is published to the docsite's /storybook/ — and the Storybook app may not import the internal entry (the lint rule limits it to Core and Lab), so a dev-only story could not reach the sheet. The sheet's browser evidence remains in #7977's description and its jsdom coverage in the sheet suite.

Changeset. #7977's pending [experimental] changeset (tokenizer-experimental-bottom-sheet.md) is removed so the release notes do not announce the sheet. check:changesets requires a categorized changeset for a @astryxdesign/core change; following the repo's internal-change convention ([chore] Internal: … Nothing a consumer sees changes., as in core-hit-area.md and animated-layout.md), tokenizer-sheet-presentation-held-back.md says the sheet is held back, reachable only through an internal entry, and that nothing a consumer sees changes.

Record (Tokenizer.spec.md). A present-tense implementation gap on DEC-3 and on each of FR16–FR24 ("Implementation gap: the sheet presentation is implemented but not yet exposed; TokenizerProps offers no experimental.presentation while its user experience is being finished, and every field renders the popover presentation."), each row's status now "Verified current behavior through the internal entry" before the gap; the readiness line says DEC-3 is implemented with that gap; Public concepts states the option is not yet exposed, consumer docs carry no experimental entry, and names the internal entry (INV13). verified_by keeps the sheet tests (they run through the entry) and adds the props-type test and the entry's test. check:knowledge is aligned.

Other callers. Searched Core, Lab, the apps and the CLI for the public option: none. MobileTokenizer (Lab) is a standalone prototype that composes its own surface, not Tokenizer's option; the one presentation: 'bottom-sheet' hit in Storybook is Selector's own prop. PowerSearch's #8001 uses the public option and is on hold; it is not touched here and will move to the internal entry when it resumes.

Writing rubric results

R1 narration: the new gap notes and the Public concepts sentence are present tense ("is implemented but not yet exposed", "offers no", "renders"); no "now"/"previously" introduced.
R2 research: none added.
R3 evidence: the FR16–FR24 status cells cite the internal entry as the verification path, not a pull request; DEC-3's gap names the entry and INV13, not this change.
R4 rejected alternatives: none added (the internal-prop alternative is argued in this description, not in the record).
R5 change references: none added; the record's pre-existing `#5804` links sit in DEC-2's standing content and are out of this change's scope.
R6 open questions: unchanged; neither lists options for an answered question.

Evidence

  • Failure before the change: TokenizerProps carried experimental.presentation; Tokenizer.doc.mjs documented it (en, zh, dense) and three public stories demonstrated it; the pending [experimental] changeset would have announced it in the next release.
  • Success after the change: experimental on Tokenizer or on a TokenizerProps extension is a type error (@ts-expect-error in the props-type test); the doc has no experimental entry; the public Storybook has no Tokenizer experimental story; the changeset is an internal [chore]; TokenizerWithPresentation from the internal entry still renders the sheet and passes the whole sheet suite.
  • Product/runtime behavior verified unchanged: every public Tokenizer renders the popover presentation exactly as before (the inline branch is untouched; Tokenizer.test.tsx passes); the sheet implementation is byte-identical apart from the signature plumbing (Tokenizer.tsx changes are the props type, the overloads and the TokenizerWithPresentation export; TokenizerBottomSheet.tsx is untouched).

Scope

  • No intended public API, product behavior, visual direction, or policy change — the public API loses an experimental option that was never released (spec:AST-017 FR21 allows its removal in a patch); runtime behavior of every public field is unchanged.
  • Product changes discovered during the work were removed or split.
  • Public text and artifacts contain no internal Meta context.

Testing

See the validation list in the pull request thread for this head: the seven CI typecheck steps, experimental-isolation, the Tokenizer suites (sheet 62, SSR 3, props-type, Tokenizer.test.tsx), the internal entry's test, the own-content adopters test, serverSafeComponents, touch-support-bundle, the ESLint plugin's no-core-internal-import test, strict lint on the changed files, Prettier, check:repo, check:knowledge, check:changesets, changeset coverage, verify-exports on the built dist, the docsite previews and build.

…ass finishes

The implementation stays, unexposed. `TokenizerProps` offers no
`experimental.presentation`; every public Tokenizer renders the inline
combobox. Astryx's own packages reach the sheet-capable signature as
`TokenizerWithPresentation` through the internal entry
`@astryxdesign/core/internal/tokenizer-presentation`
(architecture:react-component-runtime INV13), and the sheet tests run
through it. The experimental prop and example leave `Tokenizer.doc.mjs`
and the experimental stories leave Storybook; the pending
[experimental] changeset is replaced by an internal [chore] one; the
Tokenizer record carries the implementation gap on DEC-3, FR16–FR24,
Public concepts and readiness.
@vercel

vercel Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
astryx Ready Ready Preview Oct 27, 2026 7:07pm UTC

Request Review

@astracat-bot

astracat-bot Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

AI review status for this pull request.

Review status Updated
🟡 Reviewed (for maintainers only) Oct 27, 2026, 7:42 PM UTC

@imdreamrunner

Copy link
Copy Markdown
Contributor Author

/approve-spec 5861a7a

@github-actions

Copy link
Copy Markdown
Contributor

PR Analysis Report

Previews ready: Storybook and Sandbox were built with this PR's docsite. CI evidence will be added when available.

View Storybook for this PR · View Sandbox for this PR

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Oct 27, 2026

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: the hold works in types, docs and stories, but the public Tokenizer is still the same function as TokenizerWithPresentation and reads experimental.presentation at runtime, so a JavaScript caller or a JSX spread (which type-checks) still opens the unfinished sheet. Please put the option behind a non-exported boundary, for example by having the public export drop experimental before it renders a shared internal implementation, and add a test that the public barrel's Tokenizer given a spread experimental still renders the combobox; that also makes the record's and changeset's "every field renders the popover presentation" true. In the same pass, the INV7 exception in Tokenizer.spec.md still names the deleted Experimental: adaptive story as its measurement fixture, so it needs a fixture that still exists.

[Automated review]

* DEC-3). The public `Tokenizer` renders the popover presentation for every
* field.
*/
export const TokenizerWithPresentation = Tokenizer as <

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TokenizerWithPresentation is this same function, so the public Tokenizer still reads experimental.presentation at runtime (L754, L780): a JSX spread such as {...{experimental: {presentation: 'bottom-sheet' as const}}} type-checks against the public signature and opens the sheet. To make the hold real, the public export could drop experimental before rendering a shared, non-exported implementation that TokenizerWithPresentation renders with the option, plus a test that the public barrel's Tokenizer given a spread experimental renders the combobox.

'@astryxdesign/core': patch
---

[chore] Internal: Tokenizer's touch sheet presentation is held back until its user experience is finished. The implementation stays in the package, reachable only through an internal entry reserved for Astryx's own packages; `TokenizerProps` offers no `experimental.presentation`, every Tokenizer renders the inline combobox, and nothing a consumer sees changes.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Reachable only through an internal entry" and "every Tokenizer renders the inline combobox" hold only for callers that pass the attribute directly in TypeScript; a spread or a JavaScript caller still reaches the sheet through the public export (see the comment on Tokenizer.tsx).

@imdreamrunner
imdreamrunner enabled auto-merge (squash) October 27, 2026 19:45
@imdreamrunner
imdreamrunner merged commit 3ffb646 into main Oct 27, 2026
68 checks passed
vjeux added a commit to vjeux/astryx that referenced this pull request Oct 27, 2026
vjeux added a commit to vjeux/astryx that referenced this pull request Oct 27, 2026
… its internal entry) into meta#8105

useAnnounceRenderedText.adopters.test.tsx: main's test now reaches the sheet
through TokenizerWithPresentation (the internal entry). The sheet still
loads lazily, and with this branch its chunk carries the release wiring, so
the sheet case's 1 s findByLabelText still measures a cold import: main's
file alone fails the case 2 of 2 here. The untimed preload of
TokenizerBottomSheet stays, after main's import: 3 of 3.
@jiunshinn jiunshinn mentioned this pull request Oct 27, 2026
4 tasks done
@github-actions
github-actions Bot deleted the fix/tokenizer-hide-sheet-presentation branch October 28, 2026 06:17

This branch was successfully deployed

1 active deployment
Preview — 5861a7af Deployed Oct 27, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant