Skip to content

spec(AST-017): touch behavior is a default callers can override with presentation - #8273

Merged
cixzhang merged 3 commits into
mainfrom
spec/gr-touch-presentation-optout
Oct 24, 2026
Merged

cixzhang merged 3 commits into
mainfrom
spec/gr-touch-presentation-optout

Conversation

@cixzhang

@cixzhang cixzhang commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Exact decision needed

Whether callers can keep a stable component's existing surface when the component gains touch behavior, and through what API.

Existing authority searched

Decision

  • architecture:public-component-api INV16: a stable component that, under a coarse pointer, presents a different surface or switches how an open surface follows input takes one presentation prop, and a value such as presentation="popover" keeps its fine-pointer surface on every device. Touch behavior is the default where it serves touch users; the caller's explicit choice always wins. Every such touch mode is reachable by callers; thresholds and tuning stay internal. Touch styling and touch-only behavior other records define (press paint, the iOS text-size floor, a row swipe, a tooltip's touch trigger) stay with those records.
  • spec:AST-017 FR3 and DEC-23: for a touch default, that presentation value is the restoring input the Changeset names.

Rejected alternatives

  • Touch behavior that callers cannot turn off or pin.

Claim scope and non-goals

Caller control over touch presentations and modes on stable components. Which components adopt touch defaults, the touch behavior itself, and whether a given touch default is breaking stay with their owners.

Evidence and implementation relationship

Selector, MultiSelector, DropdownMenu, MoreMenu, ContextMenu, and the date and time inputs already take presentation. Related open work, not edited here: #8229 adds presentation to Popover (its 'popover' default conforms); #8195 adds a touch-tracking mode to DropdownMenu, which INV16 requires callers to be able to reach; the spec:AST-094 revision in #8052 carries the touch presentation resolver. No implementation is included.

Writing rubric results

  • R1 narration: none.
  • R2 research in the record: none.
  • R3 evidence naming a change: none; verification names test states.
  • R4 rejected alternatives over one line or outside a decision: one, inside DEC-23, one line.
  • R5 pull request or issue references remaining: none.
  • R6 ruled open questions still listing options: none.

Scope

  • This PR contains specification records only.
  • It records observable behavior and preserves equivalent internal implementations.
  • Any named internal mechanism is intentionally public, names its dependent caller/system, and explains why an equivalent implementation would not satisfy the contract.
  • Verification states the evidence layer and failure signal without prescribing CI job/workflow topology.
  • It records one intentional durable decision, not a rescue for a separable tagalong.
  • The canonical knowledge owner, affected current claims, and overlapping open work are named; any ownership collision is resolved or called out for human decision.
  • Adjacent API, visual, accessibility, composition, and implementation facts remain outside scope unless this exact decision depends on them.
  • Public text and artifacts contain no internal Meta context.

Validation

  • pnpm check:knowledge (CI lint)
  • Prettier
  • git diff --check

…the previous surface

architecture:public-component-api INV16: a stable component whose presentation
or behavior changes under a coarse pointer takes one presentation prop whose
value keeps its fine-pointer surface; touch behavior is the default where it
serves touch users, the caller's choice always wins, and every touch mode is
reachable by callers. AST-017 FR3 and DEC-23 name that presentation value as
the restoring input of a touch default.
@vercel

vercel Bot commented Oct 24, 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 24, 2026 7:07pm UTC

Request Review

@astracat-bot

astracat-bot Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

AI review status for this pull request.

Review status Updated
🟢 Reviewed (for maintainers only) Oct 24, 2026, 7:31 PM UTC

@github-actions github-actions Bot added the needs:spec-owner-review Current knowledge records await owner approval label Oct 24, 2026
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Oct 24, 2026
@github-actions

github-actions Bot commented Oct 24, 2026 •

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

@cixzhang

Copy link
Copy Markdown
Contributor Author

/approve-spec 007b941

@github-actions github-actions Bot removed the needs:spec-owner-review Current knowledge records await owner approval label Oct 24, 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.

Changes requested: the direction of INV16 and DEC-23 is owner-approved for this head, but INV16's trigger ("presentation or behavior changes under a coarse pointer", with "no touch mode is hard-coded beyond a caller's reach") also governs touch behavior that other current records define and this PR leaves unchanged.

  • Item's swipe split (spec:AST-057 FR6), the menu press model's finger rules (module:DropdownMenu/useMenuPress FR3, FR6), the iOS type floor (family:input-fields FR9) and Tooltip and HoverCard touchTrigger (spec:AST-082 FR3) now conflict with INV16.
  • The component list added to AST-017's current-state impact reads as complete but leaves out Tooltip, HoverCard and Item, and it restates facts the component records own.

Please narrow INV16 to components that present a different surface or switch an open surface's interaction mode under a coarse pointer (or amend those records in this PR), and drop or complete the list; the new commit then needs a fresh /approve-spec from an engineering owner.

[Automated review]

Comment on lines +151 to +159
- **INV16 — A caller's presentation choice wins over touch defaults.** A stable
component whose presentation or behavior changes under a coarse pointer, such
as a sheet in place of a popover or touch tracking in an open list, takes one
`presentation` prop, and a value of it, such as `presentation="popover"`,
keeps the surface the component presents with a fine pointer on every device.
Touch behavior is the component's default where it serves touch users, and a
caller's explicit choice always wins over that default. Every internal touch
mode the component switches is reachable by callers through a public prop or
value; no touch mode is hard-coded beyond a caller's reach. Thresholds and

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This trigger covers any coarse-pointer change, so it also reaches behavior other current records define and this PR leaves unchanged: Item's touch-only swipe (spec:AST-057 keeps that split internal; FR6), the press model's finger rules (module:DropdownMenu/useMenuPress FR3, FR6), the iOS type floor (family:input-fields FR9) and Tooltip and HoverCard touchTrigger (spec:AST-082 FR3). Consider scoping it to a component that presents a different surface under a coarse pointer (a sheet, drill-in view or native picker in place of its popover, flyout or typed field) or switches an open surface's interaction mode, and leaving press feedback, gestures, type floors, target sizes and hover substitutes with their owners. Otherwise those records need amending in this PR.

Comment thread docs/specs/AST-017/spec.md Outdated
Comment on lines +827 to +830
- Selector, MultiSelector, DropdownMenu, its submenus, MoreMenu, ContextMenu, and the
date and time inputs take `presentation`, so a touch default on any of them already
has its restoring value; another component that gains a touch presentation adds
`presentation` with it (FR3).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Tooltip and HoverCard (touchTrigger) and Item (swipeActions) already switch behavior on touch without presentation, so this list reads as complete when it isn't, and it restates facts the component records own. Consider stating only the rule, or naming those three as known gaps in architecture:public-component-api if INV16 keeps its broad scope.

…es; other touch rules stay with their records
@cixzhang

Copy link
Copy Markdown
Contributor Author

/approve-spec 295c532

@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.

Changes requested: the narrowed INV16 and DEC-23 are owner-approved for this head, but INV16's verification row, the FR3 sentence and DEC-23 still use the wider wording that INV16 itself just dropped.

  • The INV16 verification row (docs/architecture/public-component-api.md:248) still fails Tooltip, HoverCard, Item and the press-model menus, which INV16 now leaves with their own records.
  • The FR3 sentence and FR1–FR3 row (docs/specs/AST-017/spec.md:178-181, :854) would make a change to the menu press model name a presentation value as its migration, though no value restores it, and DEC-23's rejected line and its Deciding-specs summary overreach the same way.

Please scope those lines to touch presentations and open-surface touch modes; an engineering owner then approves the new head by commenting /approve-spec <full head SHA>, which the author may do as an engineering owner.

[Automated review]

| INV12, INV13 | Generated declaration/export/behavior inventory plus canonical-owner mapping | A reachable supporting type or behavior is called internal, or mechanical evidence is treated as permission to accept it |
| INV14 | `AppShell.test.tsx` | A component hardcodes a divergent point or treats equality as below |
| INV15 | Public-API review of the generated declaration inventory | A part or StyleX-typed styling prop ships without class-name and inline-style counterparts on the same element |
| INV16 | Public-API review of touch presentations plus coarse- and fine-pointer runtime tests | A stable component with a touch presentation or mode and no `presentation` value that keeps its fine-pointer surface on a coarse pointer; a touch mode callers cannot reach; a default that overrides an explicit caller choice |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This failure signal keeps the scope INV16 just dropped: "a touch presentation or mode and no presentation value" and "a touch mode callers cannot reach" still fail Tooltip and HoverCard (touchTrigger), Item (swipeActions) and the press-model menus (the finger rule in useMenuPress FR3), which INV16 now leaves with their records. Suggested: "A stable component that presents a different surface or switches an open surface's input mode under a coarse pointer and has no presentation value that keeps its fine-pointer surface and mode; such a mode callers cannot reach; a default that overrides an explicit caller choice".

Comment thread docs/specs/AST-017/spec.md Outdated
Comment on lines +178 to +181
option that restores the old default, which is the migration. When the new default is
touch behavior on a component whose presentation changes under a coarse pointer, that
restoring input is the component's `presentation` value that keeps its previous
surface and input mode (`architecture:public-component-api` INV16). A change to documented

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

"Touch behavior on a component whose presentation changes under a coarse pointer" also covers the press model's finger rules on DropdownMenuSubMenu, ContextMenu, DropdownMenu and Selector. presentation="flyout" and "popover" keep the press model running, so this sentence would name a migration that restores nothing. Suggested: "When the new default is a touch presentation or an open-surface touch input mode (architecture:public-component-api INV16), that restoring input is …", with the FR1–FR3 row matched.

Comment thread docs/specs/AST-017/spec.md Outdated
a functional default change names, so no touch default ships without a way back.
A touch mode hard-coded inside a component would leave callers no such choice.

Rejected: touch behavior that callers cannot turn off or pin.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This rejects more than INV16 decides: the press model's finger rule is touch behavior callers cannot turn off or pin, and INV16 keeps it with its record. Suggested: "Rejected: touch presentations or open-surface touch modes that callers cannot turn off or pin.", with the Deciding-specs line in public-component-api.md matched.

@cixzhang

Copy link
Copy Markdown
Contributor Author

/approve-spec b1bfe7f

@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.

Approval recommended: INV16 and DEC-23 are owner-approved for the latest commit, and the INV16 verification row, the FR3 sentence and DEC-23 now use INV16's narrowed scope, so they no longer reach Tooltip, HoverCard, Item or the press-model menus. Nothing further is needed from the author for this review.

[Automated review]

@cixzhang
cixzhang merged commit 55d19f3 into main Oct 24, 2026
65 checks passed
cixzhang added a commit that referenced this pull request Oct 24, 2026
… platform (#8274)

## Exact decision needed

What "compact" means when a component picks a presentation by screen size, and whether it differs by platform.

## Existing authority searched

- `spec:AST-012` FR1–FR2: width points (`md` is 768) and a closed `when` vocabulary with no height field.
- `architecture:public-component-api` INV14 and change coupling: components keep no parallel hardcoded breakpoint table.
- `component:Selector` FR4: `adaptive` uses the sheet on "compact coarse-pointer screens", with no number.
- `design:mobile-typography` DR3 uses `(width < 1024px) and (pointer: coarse)` for text sizing, a separate concern this PR leaves alone.
- No current record defines compact. Code uses `(max-width: 768px) and (pointer: coarse)`.
- Search terms: compact, 744, 768, height 500, size class, adaptive, coarse pointer, breakpoint. Overlapping open pull requests: #8062 (shared touch resolver and its compact query), #8052 (AST-094 resolver), #8015 (NumberInput steppers on coarse pointers; not a size test), #6817 (compact density, a different meaning), #8089, #8104, #8095 (phone presentations that consume the resolver).

## Decision

- `spec:AST-012` FR9 / DEC-6: a screen is compact while its width is below the effective `md` point or its height is below 500, with the same numbers on every platform (CSS px on the web, pt on iOS, dp on Android); native does not map compact to platform size classes. The theme exports this one definition; the web touch presentation resolver, Selector's `adaptive` presentation, and `@astryxdesign/native` all use it.
- `spec:AST-012` FR2: `when` gains `height`, accepting only `{below: 500}`.
- `architecture:public-component-api` INV17: a component that chooses a presentation by screen size uses that definition and keeps no numbers of its own.
- `spec:AST-082` FR18: `PortableTheme` carries the compact definition, so native reads the same numbers; FR11 and `spec:AST-093` FR3: a native choice between presentations by screen size uses it, not size classes, while the platform's own control still presents the surface.
- Compact governs presentation choice only; a layout width a caller picks, such as AppShell's `mobileNav.breakpoint`, is not compact.
- `component:Selector` records the `adaptive` edge change as pending and compatible under `spec:AST-017` FR1.

## Rejected alternatives

- Mapping compact to each platform's size classes: the same screen would be compact on one platform and not another.

## Claim scope and non-goals

The compact definition and the height condition only. Text sizing under `design:mobile-typography`, which surfaces adopt a touch presentation, and resolver code are outside this PR.

## Evidence and implementation relationship

The touch presentation resolver contract lives only in the open `spec:AST-094` revision (#8052), which this PR does not edit; it must use FR9. Native adopts FR9 when it gains a compact resolver. Behavior delta when the code conforms: a coarse-pointer screen exactly 768 wide and at least 500 tall opens the popover, and a landscape phone wider than 768 but under 500 tall opens the bottom sheet. Code follow-up belongs to separate implementation PRs. INV16 is the caller-control invariant from #8273 (merged); this PR adds INV17. No implementation is included.

## Writing rubric results

- R1 narration: none.
- R2 research in the record: none.
- R3 evidence naming a change: none; verification names edge states.
- R4 rejected alternatives over one line or outside a decision: one, inside DEC-6, one line.
- R5 pull request or issue references remaining: none added.
- R6 ruled open questions still listing options: none.

## Scope

- [x] This PR contains specification records only.
- [x] It records observable behavior and preserves equivalent internal implementations.
- [x] Any named internal mechanism is intentionally public, names its dependent caller/system, and explains why an equivalent implementation would not satisfy the contract.
- [x] Verification states the evidence layer and failure signal without prescribing CI job/workflow topology.
- [x] It records one intentional durable decision, not a rescue for a separable tagalong.
- [x] The canonical knowledge owner, affected current claims, and overlapping open work are named; any ownership collision is resolved or called out for human decision.
- [x] Adjacent API, visual, accessibility, composition, and implementation facts remain outside scope unless this exact decision depends on them.
- [x] Public text and artifacts contain no internal Meta context.

## Validation

- `pnpm check:knowledge` (CI lint)
- Prettier
- `git diff --check`
@github-actions
github-actions Bot deleted the spec/gr-touch-presentation-optout branch October 25, 2026 06:20

This branch was successfully deployed

1 active deployment
Preview — b1bfe7f1 Deployed Oct 24, 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