Skip to content

refactor(core): one press machine and paint: pressPaint and the delegated press fold into utils/pressFeedback.ts - #8379

Closed
vjeux wants to merge 614 commits into
meta:mainfrom
vjeux:uikit/c01-press-converge
Closed

vjeux wants to merge 614 commits into
meta:mainfrom
vjeux:uikit/c01-press-converge

Conversation

@vjeux

@vjeux vjeux commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Depends on #8118 and #8356 (and their predecessors); review the last three commits.

Maintainer impact

Two press machines and writers paint data-astryx-press: the controller behind usePressFeedback (utils/pressFeedback.ts), and the gesture system's delegated press and painter (gestures/delegatedPress.ts, gestures/pressPaint.ts), which no component installs. Each press change lands twice; a selection hold writes the attribute directly.

Intended invariant

One press machine and one writer of the press attribute, as settled in #8073's review; usePressFeedback's API, every press's paint, clocks and release, and #8118's layers stay as they are (design:user-states DR1, DR5; spec:AST-094 FR11).

Change

  • paintPress and readPressPaint move into utils/pressFeedback.ts, and the controller writes through them: a fade's clock and the attribute never drift apart, and a press never overwrites a held row.
  • selectionHold.ts writes and clears held through paintPress.
  • gestures/delegatedPress.ts and gestures/pressPaint.ts are removed, with their internal exports.
  • PressTracker reports UIControl's control events and paints nothing; the gesture host drops its delegated consumer, which nothing uses.
  • PressTracker and usePressTracker lose their highlight options and PRESS_PROFILES; no package entry point exports them.
  • The base merge carries fix(core): one input stream on the window's capture phase for the press feedback and the gesture host #8356 onto fix(core): a control's press release runs on the compositor #8118's controller (input stream, spec:AST-094 FR41's native long-press selection, FR24's coarse-only touch listeners, subscribePressPaint); this PR drops isPressFeedbackInstalled with its only caller, and the one writer keeps reporting only the controller's paints.
  • Size: about +0.06 KB gzip JS per pressable import (Button 47.31 KB at this head), CSS +0.

By design (spec:AST-094 FR11): a control's press ends when the browser takes the touch, and activation stays the browser's click; UIControl's tracking out to 70 pt and its re-highlight on the way back are not ported.

Evidence

  • Failure before: with two writers (the base's gestures/pressPaint.ts and the controller), another painter's fade cut the controller's release short; the new test fails there.
  • After: it passes; the four moved press-paint tests pass on both.
  • Behavior unchanged, real touches (Android's hold paced by the injector):
Unchanged from #8118 iOS 26.2 Safari Android 15 Chromium 158
Button: a tap, then a held press
A row held through a push, deselected on Back

Scope

  • No intended public API, product behavior, visual direction, or policy change.
  • Product changes discovered during the work were removed or split.
  • Public text and artifacts contain no internal Meta context.

Testing

  • pnpm -F @astryxdesign/core typecheck; pnpm -F @astryxdesign/lab typecheck; pnpm check:repo; pnpm check:changesets; lint and prettier on touched files.
  • pnpm vitest run scripts/build-css.test.mjs packages/core/src/{utils,gestures,hooks,Item,List,TreeList,Button,ClickableCard,SelectableCard,Thumbnail,IconButton,ToggleButton,motion,RadioList,CheckboxList,Switch,TabList,AlertDialog,DropdownMenu} packages/lab/src internal/interaction-harness/src: 4,069 pass (DropdownMenuLazySheet, whose beforeAll import can pass its 10 s hook timeout under the full parallel run, passes alone). The CLI discovery and doc suites: 1,102 pass.
  • pnpm storybook:build, then pnpm test:interaction --project chromium Button List Item TreeList ClickableCard SelectableCard gestures motion internal/interaction-harness: 128 pass, 3 skip.
  • WebKit: node internal/interaction-harness/scripts/webkit-container.mjs --config playwright.interaction.config.ts --project=webkit ButtonPressRelease ButtonPress ListRowPress gestures: 37 pass, 19 skip.
  • pnpm exec playwright test PressModality.a11y CardPress.a11y PressedState.a11y MenuPress.a11y --project chromium: 30 pass.

Stack (merge in this order): #8118's stack, then #8270 → #8309 → #8315 → #8336 → #8320 → #8293 → #8356 → this PR.

@vercel

vercel Bot commented Oct 25, 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 26, 2026 3:13am UTC

Request Review

@astracat-bot

astracat-bot Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

AI review status for this pull request.

Review status Updated
❓ Needs maintainer input (for maintainers only) Oct 26, 2026, 3:44 AM UTC

@github-actions github-actions Bot added the needs:design-review Affects visuals — Design should review label Oct 25, 2026
@vjeux

vjeux commented Oct 25, 2026

Copy link
Copy Markdown
Contributor Author

Gestures-side review at 8723e79:

  • The removals are complete. No references remain anywhere in packages, apps or docs to delegatedPress, gestures/pressPaint, installPressAttribute / usePressAttribute, addDelegatedConsumer / DelegatedConsumerType, or the press tracker's removed highlight options.
  • Checked at this head:
    • tsc is clean.
    • The gestures, utils, hooks, List, Item and Button suites pass (1,650 tests).
    • Changesets, sync-exports and check:sync are clean.
  • One fix, in gestures/README.md. The last two commits match the press-tracker strip, except that the README conflict resolution kept a two-line placeholder and dropped this PR's own paragraph on paintPress, which covers the held value and onlyFrom: ['held']. Callers need that paragraph, so please put it back in place of the two lines.
  • Optional, one source. With the press tracker's flash gone, nothing reads UIKIT_GESTURES.press.quickTapFlash anymore.
    • Meanwhile pressGesture.ts keeps its own PRESS_FLASH_MS = 100 and PRESS_ONSET_MS = 150 beside the table's quickTapFlash and contentTouchDelay. The press tracker's keepsTouch delivery still reads contentTouchDelay.
    • Either drop the unused entry, or pin both pairs equal in a test so they can't drift.
    • I wouldn't import the table into pressGesture.ts: that would add it to every pressable page's bundle.

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

This cannot be approved until an engineering owner decides on draft spec:AST-094: it is the only authority for every touch press, motion and gesture change in this diff, and it proposes amendments to several current records. An engineering owner records that decision by commenting /approve-spec 8723e795a9d6dee9c22f65ef2bcc692ff375fcef on this pull request, and the author can do so if they are an engineering owner; FR8 should first conform to the current reduced-motion record (opacity only, 200 ms or less, no spring). Separately, these fixes are needed:

  • Rebase once the prerequisite pull requests (#8118's stack through #8356) have landed, so the diff holds this pull request's three commits instead of 42,628 authored lines.
  • Gate the list row press layer (interactionOverlayStyles.cell) on @media (pointer: coarse) like Button's, since it now hides a desktop row's own ::before decoration, which spec:AST-017 FR59 rules out for touch work.
  • Key the divider-hiding rule on a finger press so a trackpad press on a tablet keeps the dividers, and add fine-pointer before-and-after evidence for the mouse and Space press paint on touch-first devices.
  • Update the pending changesets that still describe the delegated press, the press profiles, highlightDelay / quickTapFlash and VelocityStrategy.

[Automated review]

animationDuration: null,
animationTimingFunction: null,
animationFillMode: null,
isolation: 'isolate',

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 layer has no @media (pointer: coarse) gate, unlike control below, so on a desktop every interactive Item, ListItem and TreeList row gets isolation: isolate and an opacity-0 ::before, and a row's own ::before decoration from xstyle is hidden at rest. spec:AST-017 FR59 keeps fine-pointer appearance unchanged for touch work; gating this layer the way control is gated would fix it.

default: colorVars['--color-border'],
'@media (pointer: coarse)': {
default: null,
'[data-astryx-press="on"]': 'transparent',

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

A mouse or trackpad press on a touch-first device also writes data-astryx-press="on" (pressButton, whose buttonDown step paints on), and this rule keys only on the coarse primary pointer. So a trackpad press on a tablet hides the dividers, although the comment above says they stay drawn with a mouse. Could the rule key on a finger press instead, with a test of a mouse press under a coarse primary pointer?

on: a transition that travels becomes a cross-fade carrying the same change
of state. An entrance lands in place and fades in, an exit fades out in
place, and any other move fades through. A navigation push or pop
cross-fades over 0.5 s on the ease-in-out curve; a sheet, a full-screen

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Under Reduce Motion, current design:reduced-motion DR2 limits a coarse-pointer transition to an opacity-only fade of 200 ms or less, and DR1 rules out springs. This 0.5 s cross-fade and the menu spring go past both, and the record's current-state impact does not list that record. The code already follows DR2 (reducedMotionCrossFadeMs: 200 in motion/uikit/timing.ts).

Comment thread .changeset/gesture-press-tracking.md Outdated
'@astryxdesign/core': patch
---

[chore] UIControl press tracking with control and cell profiles, the shared press paint, delegated press tracking and the gesture hooks. Not exported from the package root; touch presentations reach them through the experimental subpaths (see their entry). No component uses them yet.

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 pull request removes the control and cell profiles, the gestures press paint and the delegated press tracking, so if this entry ships with the rest of the stack the changelog announces pieces that do not exist. The same goes for gesture-hook-fixes.md (highlightDelay, quickTapFlash), gesture-host-fixes.md (the delegated press) and touch-experimental-subpaths.md (VelocityStrategy).

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Oct 25, 2026
@vjeux
vjeux force-pushed the uikit/c01-press-converge branch from 8723e79 to f68068e Compare October 25, 2026 09:42
@vjeux
vjeux force-pushed the uikit/c01-press-converge branch from f68068e to 35f10e7 Compare October 25, 2026 11:41

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

This can't be approved yet: the touch press, list and theme-motion changes this diff carries from the stack have no current spec authority, since they rest on draft spec:AST-094, which is only proposed in #8378, and the 250 ms ease-in-out touch release contradicts the 200 ms in component:Button FR15. An engineering owner needs to decide whether spec:AST-094 governs these changes and amend FR15, recording the approval on #8378 with /approve-spec and that pull request's full head SHA so the record becomes current on main (the author can do this as an engineering owner), or say which changes should leave the stack. Separately, these fixes are needed:

  • Rebase once the prerequisite pull requests land, so the diff holds this pull request's three commits instead of 42,887 authored lines.
  • interactionOverlayStyles.cell replaces the row's animationName without the Reduce Motion arm, so list rows still fade for 200 ms with a fine pointer; spreading strengthReleaseOutsideCoarse there fixes it.
  • The divider rule keys only on a coarse primary pointer, so a trackpad or mouse press on a tablet hides the dividers; key it on a finger's press and show fine-pointer before and after.
  • gesture-press-tracking.md still announces the delegated press tracking this pull request removes.

[Automated review]

// declares it (its clock and curve are untouched).
animationName: {
default: null,
[PRESSED_FADING]: {default: pressRelease, [COARSE]: 'none'},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Composed after the row's overlay variant, this animationName replaces the variant's whole, so it drops the '@media (prefers-reduced-motion: reduce) and (not (pointer: coarse))': 'none' arm. With a fine primary pointer and Reduce Motion, a finger's press on an interactive Item, ListItem or TreeList row still fades for 200 ms (in Chromium the row keeps the strength keyframes while Button reads animation-name: none), against design:reduced-motion DR3 and press-paint-reduced-motion.md. Spreading ...strengthReleaseOutsideCoarse here would keep this arm set plus the Reduce Motion one.

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

This can't be approved yet: the touch press, list and theme-motion changes this diff carries from the stack have no current spec authority, since the record proposed for them, draft spec:AST-094, is only in #8378, and the 250 ms ease-in-out touch release contradicts the 200 ms in component:Button FR15. An engineering owner needs to decide whether spec:AST-094 governs these changes and amend FR15, recording the approval on #8378 by commenting /approve-spec with that pull request's full head SHA so the record becomes current on main (the author can do this as an engineering owner), or say which changes should leave the stack. Separately, these fixes are needed:

  • Rebase once the prerequisite pull requests land, so the diff holds this pull request's three commits instead of 42,858 authored lines.
  • interactionOverlayStyles.cell replaces the row's animationName without the Reduce Motion arm, so list rows still fade for 200 ms with a fine pointer; spreading strengthReleaseOutsideCoarse there fixes it.
  • The divider rule and holdSelection key only on a coarse primary pointer, so a mouse or trackpad press on a tablet hides the dividers and is held; key them on a finger's press and show fine-pointer before and after.
  • gesture-press-tracking.md and line 228 of the gestures README still describe the delegated press this pull request removes.

[Automated review]

// declares it (its clock and curve are untouched).
animationName: {
default: null,
[PRESSED_FADING]: {default: pressRelease, [COARSE]: 'none'},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Composed after the row's overlay variant, this animationName replaces the variant's whole, so it drops the '@media (prefers-reduced-motion: reduce) and (not (pointer: coarse))': 'none' arm. With a fine primary pointer and Reduce Motion, a finger's press on an interactive Item, ListItem or TreeList row still fades for 200 ms, against design:reduced-motion DR3 and press-paint-reduced-motion.md. Spreading ...strengthReleaseOutsideCoarse here instead keeps this arm set plus the Reduce Motion one.

default: colorVars['--color-border'],
'@media (pointer: coarse)': {
default: null,
'[data-astryx-press="on"]': 'transparent',

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

On a touch-first device a mouse or trackpad press also writes data-astryx-press="on" (pressButton in utils/pressFeedback.ts), and these arms key only on the coarse primary pointer, so a trackpad press on a tablet hides the dividers although the comment above says they stay drawn with a mouse (spec:AST-017 FR59). Could this key on a finger's press, with a test of a mouse press under a coarse primary pointer?

);
if (
row == null ||
!isTouch(row.ownerDocument.defaultView) ||

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 checks only the device's primary pointer, so on a tablet a mouse or trackpad click also gets a hold, while list-selection-hold.md says the hold is null with a mouse. Checking how the activation was made (or a finger marker from the press controller) would match the changeset.

'@astryxdesign/core': patch
---

[chore] Internal: UIControl press tracking with control and cell profiles, the shared press paint, delegated press tracking and the gesture hooks. Not exported from the package entry point; no component uses them yet.

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 pull request removes the tracker's control and cell profiles, the gestures press paint and the delegated press tracking, so if the stack ships in one release the changelog lists them beside press-machine-one-writer.md, which says they are gone. Could this entry describe only what remains?

Comment thread packages/core/src/gestures/README.md Outdated
off the iOS callout and text selection on its element.

While a finger or a pen is down, the host turns them off too on the
element of a press tracker (attached or delegated: a control or a cell)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The delegated press tracker is gone after this pull request, so "attached or delegated: a control or a cell" can drop "or delegated".

@github-actions

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR

🧪 Sandbox Preview

View Sandbox for this PR

Modified Components

Button (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Entry File (ESM) 712B 712B 0B
Lines of Code 562 563 -
Complexity Very High Very High (78) -
ClickableCard (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Entry File (ESM) 427B 427B 0B
Lines of Code 229 230 -
Complexity High High (20) -
ContextMenu (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Entry File (ESM) 1.1KB 1.1KB 0B
Lines of Code 639 639 -
Complexity Very High Very High (84) -
Item (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Entry File (ESM) 284B 284B 0B
Lines of Code 1366 1369 -
Complexity Very High Very High (122) -
MoreMenu (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Entry File (ESM) 219B 219B 0B
Lines of Code 87 87 -
Complexity Low Low (4) -
MultiSelector (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Entry File (ESM) 273B 273B 0B
Lines of Code 2626 2626 -
Complexity Very High Very High (338) -
SelectableCard (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Entry File (ESM) 108B 108B 0B
Lines of Code 305 306 -
Complexity Very High Very High (33) -
Thumbnail (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Entry File (ESM) 164B 164B 0B
Lines of Code 339 340 -
Complexity Very High Very High (39) -
TreeList (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Entry File (ESM) 648B 648B 0B
Lines of Code 872 876 -
Complexity Very High Very High (100) -

Component Size

Component Import before Import after Delta CSS before CSS after Delta
core/AlertDialog 51.3KB 54.7KB +3.4KB ⚠️ 12.2KB 13.0KB +814B
core/AppShell 52.5KB 55.6KB +3.2KB ⚠️ 11.4KB 12.2KB +829B
core/AspectRatio 3.6KB 3.9KB +365B 3.3KB 4.2KB +868B
core/Avatar 34.6KB 34.9KB +321B 6.2KB 7.0KB +829B
core/AvatarGroup 36.9KB 37.2KB +307B 6.3KB 7.1KB +822B
core/AvatarGroupOverflow 37.0KB 40.3KB +3.3KB ⚠️ 6.2KB 7.0KB +827B
core/AvatarStatusDot 6.9KB 7.3KB +383B 3.3KB 4.1KB +872B
core/Badge 3.7KB 4.1KB +372B 3.6KB 4.5KB +871B
core/Banner 44.6KB 47.9KB +3.4KB ⚠️ 9.5KB 10.4KB +829B
core/BaseTypeahead 50.7KB 54.1KB +3.4KB ⚠️ 9.7KB 10.5KB +835B
core/Blockquote 3.4KB 3.8KB +373B 3.3KB 4.1KB +883B
core/BottomSheet 25.8KB 26.2KB +361B 7.5KB 8.3KB +843B
core/BottomSheetSwitcher 9.1KB 9.4KB +369B 3.2KB 4.0KB +861B
core/BreadcrumbItem 62.7KB 66.0KB +3.4KB ⚠️ 10.8KB 11.6KB +838B
core/Breadcrumbs 22.3KB 22.7KB +375B 3.1KB 4.0KB +883B
core/Button 40.1KB 43.5KB +3.4KB ⚠️ 9.0KB 9.8KB +820B
core/ButtonGroup 8.3KB 8.6KB +372B 3.2KB 4.0KB +877B
core/Calendar 51.8KB 55.2KB +3.4KB ⚠️ 9.8KB 10.6KB +818B
core/Card 6.3KB 6.7KB +367B 6.2KB 7.0KB +885B
core/Carousel 45.8KB 49.1KB +3.4KB ⚠️ 10.0KB 10.8KB +822B
core/Center 4.0KB 4.4KB +372B 4.4KB 5.3KB +885B
core/ChatComposer 57.2KB 60.5KB +3.3KB ⚠️ 10.5KB 11.3KB +825B
core/ChatComposerDrawer 23.7KB 24.1KB +394B 4.3KB 5.2KB +859B
core/ChatComposerInput 52.3KB 55.7KB +3.3KB ⚠️ 9.8KB 10.6KB +826B
core/ChatComposerTokenElement 52.3KB 55.7KB +3.3KB ⚠️ 9.8KB 10.6KB +826B
core/ChatDictationButton 43.4KB 46.8KB +3.4KB ⚠️ 9.2KB 10.0KB +820B
core/ChatLayout 45.8KB 49.1KB +3.3KB ⚠️ 9.7KB 10.5KB +821B
core/ChatLayoutScrollButton 43.3KB 46.6KB +3.4KB ⚠️ 9.3KB 10.1KB +820B
core/ChatMessage 22.9KB 23.3KB +370B 3.4KB 4.3KB +879B
core/ChatMessageBubble 6.9KB 7.2KB +369B 3.5KB 4.3KB +875B
core/ChatMessageList 28.3KB 28.7KB +387B 7.6KB 8.4KB +837B
core/ChatMessageMetadata 25.7KB 26.0KB +356B 3.7KB 4.5KB +846B
core/ChatSendButton 42.8KB 46.1KB +3.3KB ⚠️ 9.0KB 9.8KB +820B
core/ChatSystemMessage 6.6KB 7.0KB +375B 3.5KB 4.4KB +881B
core/ChatTokenizedText 6.8KB 7.1KB +371B 3.7KB 4.5KB +870B
core/ChatToolCalls 31.7KB 32.0KB +367B 8.7KB 9.5KB +829B
core/CheckIndicator 8.9KB 9.2KB +372B 3.4KB 4.3KB +875B
core/CheckboxIndicator 4.0KB 4.3KB +371B 3.7KB 4.5KB +849B
core/CheckboxInput 46.5KB 49.8KB +3.3KB ⚠️ 9.2KB 10.0KB +811B
core/CheckboxList 43.0KB 43.3KB +377B 7.9KB 8.7KB +821B
core/CheckboxListItem 50.6KB 54.0KB +3.4KB ⚠️ 10.3KB 11.2KB +964B
core/Citation 25.8KB 26.2KB +381B 4.0KB 4.8KB +869B
core/ClickableCard 12.7KB 16.0KB +3.3KB ⚠️ 6.8KB 7.6KB +857B
core/Code 3.4KB 3.8KB +378B 3.2KB 4.1KB +876B
core/CodeBlock 55.5KB 58.9KB +3.4KB ⚠️ 10.4KB 11.3KB +839B
core/Collapsible 11.6KB 14.9KB +3.3KB ⚠️ 4.1KB 4.9KB +869B
core/CollapsibleGroup 6.3KB 6.6KB +368B 3.1KB 3.9KB +882B
core/CommandPalette 49.0KB 52.4KB +3.4KB ⚠️ 11.6KB 12.4KB +830B
core/CommandPaletteEmpty 6.0KB 6.3KB +367B 3.2KB 4.0KB +879B
core/CommandPaletteFooter 23.2KB 23.5KB +380B 3.4KB 4.3KB +876B
core/CommandPaletteGroup 3.3KB 3.7KB +368B 3.2KB 4.0KB +882B
core/CommandPaletteInput 31.7KB 32.1KB +368B 8.0KB 8.8KB +847B
core/CommandPaletteItem 8.3KB 11.6KB +3.3KB ⚠️ 3.3KB 4.2KB +874B
core/CommandPaletteList 22.3KB 22.7KB +371B 3.1KB 4.0KB +881B
core/ComplexSelector 52.1KB 55.5KB +3.4KB ⚠️ 10.3KB 11.2KB +827B
core/ContextMenu 73.9KB 77.3KB +3.4KB ⚠️ 14.2KB 15.2KB +971B
core/ContextMenuItem 16.4KB 19.8KB +3.4KB ⚠️ 5.0KB 5.8KB +861B
core/DateInput 89.6KB 92.8KB +3.3KB ⚠️ 14.3KB 15.1KB +828B
core/DateRangeInput 61.3KB 64.6KB +3.3KB ⚠️ 10.9KB 11.7KB +818B
core/DateTimeInput 98.9KB 102.1KB +3.2KB ⚠️ 14.7KB 15.5KB +834B
core/Dialog 13.6KB 14.0KB +367B 6.9KB 7.7KB +820B
core/DialogHeader 45.7KB 49.1KB +3.4KB ⚠️ 9.5KB 10.3KB +821B
core/Divider 6.3KB 6.7KB +362B 3.4KB 4.3KB +879B
core/Drawer 22.8KB 23.2KB +357B 7.9KB 8.7KB +840B
core/DrawerHeader 45.7KB 49.1KB +3.4KB ⚠️ 10.9KB 11.7KB +821B
core/DropdownMenu 69.0KB 72.5KB +3.4KB ⚠️ 14.4KB 15.3KB +973B
core/DropdownMenuCheckboxItem 16.0KB 19.4KB +3.4KB ⚠️ 5.4KB 6.2KB +831B
core/DropdownMenuDivider 6.5KB 6.8KB +370B 3.4KB 4.3KB +882B
core/DropdownMenuGroup 5.9KB 6.3KB +366B 3.1KB 4.0KB +882B
core/DropdownMenuItem 15.3KB 18.7KB +3.4KB ⚠️ 4.9KB 5.8KB +861B
core/DropdownMenuRadioGroup 5.9KB 6.3KB +360B 3.1KB 3.9KB +881B
core/DropdownMenuRadioItem 16.0KB 19.5KB +3.4KB ⚠️ 5.4KB 6.2KB +831B
core/DropdownMenuSubMenu 54.5KB 57.7KB +3.2KB ⚠️ 9.3KB 10.1KB +833B
core/EmptyState 7.5KB 7.9KB +369B 3.4KB 4.2KB +876B
core/Field 41.2KB 41.6KB +370B 7.7KB 8.5KB +822B
core/FieldLabel 36.9KB 37.2KB +302B 6.4KB 7.2KB +821B
core/FieldStatus 10.2KB 10.5KB +370B 4.0KB 4.8KB +833B
core/FileInput 50.6KB 53.9KB +3.3KB ⚠️ 10.1KB 10.9KB +815B
core/FormLayout 6.2KB 6.5KB +373B 3.2KB 4.1KB +879B
core/Grid 4.2KB 4.6KB +375B 3.5KB 4.4KB +887B
core/GridSpan 3.3KB 3.7KB +369B 3.1KB 4.0KB +884B
core/HStack 7.2KB 7.5KB +376B 4.8KB 5.6KB +887B
core/Heading 9.0KB 9.4KB +366B 6.7KB 7.5KB +832B
core/Icon 8.7KB 9.0KB +367B 3.4KB 4.3KB +875B
core/IconButton 40.2KB 43.5KB +3.4KB ⚠️ 9.0KB 9.8KB +820B
core/InputGroup 41.7KB 42.1KB +374B 7.8KB 8.6KB +823B
core/InputGroupText 6.1KB 6.5KB +365B 3.4KB 4.2KB +882B
core/Item 11.2KB 14.8KB +3.6KB ⚠️ 4.5KB 5.3KB +857B
core/Kbd 6.6KB 6.9KB +366B 3.3KB 4.2KB +876B
core/LayerProvider 54.4KB 57.8KB +3.4KB ⚠️ 9.9KB 10.7KB +828B
core/Layout 8.0KB 8.4KB +380B 5.3KB 6.2KB +882B
core/LayoutContent 7.3KB 7.7KB +372B 4.8KB 5.7KB +889B
core/LayoutFooter 7.2KB 7.5KB +372B 4.6KB 5.5KB +891B
core/LayoutHeader 7.2KB 7.6KB +377B 4.6KB 5.5KB +889B
core/LayoutPanel 7.4KB 7.8KB +373B 4.7KB 5.6KB +889B
core/Lightbox 46.4KB 49.8KB +3.4KB ⚠️ 9.6KB 10.4KB +829B
core/Link 40.6KB 43.9KB +3.3KB ⚠️ 7.4KB 8.2KB +821B
core/List 6.6KB 7.0KB +371B 3.3KB 4.1KB +882B
core/ListItem 50.1KB 53.4KB +3.3KB ⚠️ 10.3KB 11.2KB +964B
core/Markdown 133.2KB 136.7KB +3.5KB ⚠️ 16.9KB 17.9KB +976B
core/MetadataList 23.0KB 23.4KB +366B 3.5KB 4.3KB +879B
core/MetadataListItem 6.3KB 6.7KB +364B 3.3KB 4.1KB +882B
core/MobileNav 45.7KB 49.0KB +3.3KB ⚠️ 9.8KB 10.6KB +828B
core/MobileNavToggle 43.2KB 46.5KB +3.4KB ⚠️ 9.2KB 10.0KB +820B
core/MoreMenu 69.2KB 72.6KB +3.5KB ⚠️ 14.4KB 15.3KB +973B
core/MultiSelector 71.9KB 75.1KB +3.2KB ⚠️ 14.1KB 14.9KB +808B
core/NavHeadingMenu 8.8KB 9.1KB +377B 3.1KB 4.0KB +881B
core/NavIcon 3.3KB 3.7KB +374B 3.2KB 4.0KB +873B
core/NumberInput 52.5KB 55.8KB +3.3KB ⚠️ 10.4KB 11.2KB +829B
core/Outline 28.5KB 31.8KB +3.3KB ⚠️ 3.9KB 4.7KB +859B
core/OverflowList 8.4KB 8.7KB +374B 3.4KB 4.2KB +871B
core/Overlay 14.2KB 14.5KB +341B 3.7KB 4.5KB +841B
core/Pagination 83.6KB 87.0KB +3.4KB ⚠️ 14.8KB 15.6KB +823B
core/Popover 44.1KB 47.5KB +3.3KB ⚠️ 9.2KB 10.0KB +820B
core/PowerSearch 143.9KB 147.3KB +3.3KB ⚠️ 18.1KB 18.9KB +828B
core/ProgressBar 7.6KB 7.9KB +357B 6.4KB 7.2KB +822B
core/RadioIndicator 3.7KB 4.1KB +371B 3.6KB 4.4KB +851B
core/RadioList 42.5KB 42.9KB +385B 7.8KB 8.6KB +825B
core/RadioListItem 49.2KB 52.5KB +3.3KB ⚠️ 9.4KB 10.2KB +816B
core/ResizeHandle 25.0KB 25.4KB +388B 3.7KB 4.6KB +856B
core/Section 7.4KB 7.8KB +380B 6.0KB 6.9KB +888B
core/SegmentedControl 35.9KB 36.3KB +385B 6.2KB 7.0KB +827B
core/SegmentedControlItem 8.5KB 11.8KB +3.3KB ⚠️ 3.7KB 4.6KB +866B
core/SelectableCard 12.6KB 16.0KB +3.4KB ⚠️ 7.0KB 7.8KB +852B
core/Selector 75.1KB 78.3KB +3.2KB ⚠️ 14.5KB 15.3KB +828B
core/SelectorOption 14.4KB 17.9KB +3.5KB ⚠️ 4.8KB 5.7KB +854B
core/SideNav 52.8KB 56.1KB +3.3KB ⚠️ 10.3KB 11.1KB +833B
core/SideNavCollapseButton 43.5KB 46.9KB +3.4KB ⚠️ 9.2KB 10.0KB +821B
core/SideNavHeading 51.6KB 54.9KB +3.3KB ⚠️ 9.9KB 10.7KB +825B
core/SideNavItem 51.3KB 54.6KB +3.3KB ⚠️ 9.9KB 10.7KB +828B
core/SideNavSection 6.4KB 6.7KB +360B 3.5KB 4.3KB +873B
core/Skeleton 3.7KB 4.0KB +364B 3.5KB 4.3KB +853B
core/Slider 45.5KB 45.9KB +379B 8.3KB 9.1KB +818B
core/Spinner 26.2KB 26.6KB +392B 7.4KB 8.2KB +836B
core/Stack 6.9KB 7.3KB +365B 4.8KB 5.6KB +887B
core/StackItem 5.9KB 6.3KB +362B 3.2KB 4.0KB +882B
core/StatusDot 16.1KB 16.4KB +314B 6.0KB 6.8KB +833B
core/Step 32.2KB 35.6KB +3.3KB ⚠️ 5.1KB 5.9KB +833B
core/Stepper 44.3KB 47.7KB +3.4KB ⚠️ 9.3KB 10.1KB +821B
core/Switch 45.4KB 48.7KB +3.3KB ⚠️ 9.1KB 9.9KB +821B
core/Tab 9.6KB 12.9KB +3.3KB ⚠️ 4.0KB 4.8KB +842B
core/TabList 37.3KB 37.7KB +397B 7.0KB 7.8KB +843B
core/TabMenu 48.5KB 51.8KB +3.3KB ⚠️ 9.8KB 10.6KB +818B
core/Table 80.1KB 83.4KB +3.4KB ⚠️ 14.6KB 15.6KB +973B
core/TableBody 3.2KB 3.5KB +369B 3.0KB 3.9KB +882B
core/TableCell 74.9KB 78.3KB +3.3KB ⚠️ 14.4KB 15.3KB +975B
core/TableFooter 3.2KB 3.5KB +366B 3.0KB 3.9KB +882B
core/TableHeader 3.2KB 3.5KB +367B 3.0KB 3.9KB +882B
core/TableHeaderCell 74.7KB 78.1KB +3.3KB ⚠️ 14.3KB 15.3KB +976B
core/TableRow 6.1KB 6.5KB +377B 3.4KB 4.3KB +877B
core/TableSelectionToolbar 49.1KB 52.4KB +3.3KB ⚠️ 11.0KB 11.8KB +827B
core/Text 8.5KB 8.8KB +371B 6.7KB 7.5KB +832B
core/TextArea 46.0KB 46.3KB +387B 9.1KB 9.9KB +823B
core/TextInput 50.0KB 53.3KB +3.3KB ⚠️ 10.2KB 11.0KB +826B
core/Thumbnail 47.0KB 50.4KB +3.4KB ⚠️ 10.8KB 11.5KB +807B
core/TimeInput 76.1KB 79.4KB +3.3KB ⚠️ 13.2KB 14.1KB +831B
core/Timer 9.1KB 9.5KB +389B 6.7KB 7.5KB +832B
core/Timestamp 27.4KB 28.2KB +862B 9.3KB 10.1KB +820B
core/Toast 51.2KB 54.6KB +3.4KB ⚠️ 9.5KB 10.3KB +820B
core/ToggleButton 41.0KB 44.4KB +3.4KB ⚠️ 9.1KB 9.9KB +819B
core/ToggleButtonGroup 6.2KB 6.6KB +372B 3.1KB 4.0KB +881B
core/Token 29.5KB 32.8KB +3.3KB ⚠️ 4.3KB 5.2KB +851B
core/Tokenizer 61.2KB 64.5KB +3.4KB ⚠️ 11.4KB 12.2KB +822B
core/Toolbar 36.9KB 37.2KB +373B 7.6KB 8.4KB +873B
core/TopNav 46.6KB 49.9KB +3.3KB ⚠️ 10.1KB 10.9KB +829B
core/TopNavHeading 51.0KB 54.3KB +3.3KB ⚠️ 9.7KB 10.5KB +821B
core/TopNavItem 8.9KB 12.3KB +3.3KB ⚠️ 3.7KB 4.6KB +869B
core/TopNavMegaMenu 51.0KB 54.3KB +3.3KB ⚠️ 10.5KB 11.4KB +833B
core/TopNavMegaMenuFeaturedCard 6.6KB 7.0KB +370B 3.3KB 4.1KB +884B
core/TopNavMegaMenuItem 9.0KB 12.3KB +3.3KB ⚠️ 3.9KB 4.8KB +866B
core/TopNavMenu 50.5KB 53.7KB +3.3KB ⚠️ 9.9KB 10.7KB +828B
core/TreeList 32.4KB 36.0KB +3.6KB ⚠️ 4.5KB 5.4KB +847B
core/Typeahead 57.7KB 61.1KB +3.4KB ⚠️ 11.0KB 11.8KB +816B
core/TypeaheadItem 6.1KB 6.4KB +365B 3.3KB 4.2KB +879B
core/VStack 7.2KB 7.5KB +376B 4.8KB 5.6KB +887B

Sizes are gzip. Import counts the JavaScript the import loads eagerly; CSS counts the package stylesheet rules referenced by the modules it can load from its own package, lazily loaded ones included.

⚠️ Touch-only size budget

These components grew past the touch-only budget (2 KB gzip JavaScript or 1 KB gzip CSS per component). If the growth runs only on a coarse pointer, load its JavaScript lazily so the import does not carry it, or justify the cost in the pull request description; CSS stays in the package stylesheet, so justify it.

Component JavaScript CSS
core/AlertDialog +3.4KB ⚠️ +814B
core/AppShell +3.2KB ⚠️ +829B
core/AvatarGroupOverflow +3.3KB ⚠️ +827B
core/Banner +3.4KB ⚠️ +829B
core/BaseTypeahead +3.4KB ⚠️ +835B
core/BreadcrumbItem +3.4KB ⚠️ +838B
core/Button +3.4KB ⚠️ +820B
core/Calendar +3.4KB ⚠️ +818B
core/Carousel +3.4KB ⚠️ +822B
core/ChatComposer +3.3KB ⚠️ +825B
core/ChatComposerInput +3.3KB ⚠️ +826B
core/ChatComposerTokenElement +3.3KB ⚠️ +826B
core/ChatDictationButton +3.4KB ⚠️ +820B
core/ChatLayout +3.3KB ⚠️ +821B
core/ChatLayoutScrollButton +3.4KB ⚠️ +820B
core/ChatSendButton +3.3KB ⚠️ +820B
core/CheckboxInput +3.3KB ⚠️ +811B
core/CheckboxListItem +3.4KB ⚠️ +964B
core/ClickableCard +3.3KB ⚠️ +857B
core/CodeBlock +3.4KB ⚠️ +839B
core/Collapsible +3.3KB ⚠️ +869B
core/CommandPalette +3.4KB ⚠️ +830B
core/CommandPaletteItem +3.3KB ⚠️ +874B
core/ComplexSelector +3.4KB ⚠️ +827B
core/ContextMenu +3.4KB ⚠️ +971B
core/ContextMenuItem +3.4KB ⚠️ +861B
core/DateInput +3.3KB ⚠️ +828B
core/DateRangeInput +3.3KB ⚠️ +818B
core/DateTimeInput +3.2KB ⚠️ +834B
core/DialogHeader +3.4KB ⚠️ +821B
core/DrawerHeader +3.4KB ⚠️ +821B
core/DropdownMenu +3.4KB ⚠️ +973B
core/DropdownMenuCheckboxItem +3.4KB ⚠️ +831B
core/DropdownMenuItem +3.4KB ⚠️ +861B
core/DropdownMenuRadioItem +3.4KB ⚠️ +831B
core/DropdownMenuSubMenu +3.2KB ⚠️ +833B
core/FileInput +3.3KB ⚠️ +815B
core/IconButton +3.4KB ⚠️ +820B
core/Item +3.6KB ⚠️ +857B
core/LayerProvider +3.4KB ⚠️ +828B
core/Lightbox +3.4KB ⚠️ +829B
core/Link +3.3KB ⚠️ +821B
core/ListItem +3.3KB ⚠️ +964B
core/Markdown +3.5KB ⚠️ +976B
core/MobileNav +3.3KB ⚠️ +828B
core/MobileNavToggle +3.4KB ⚠️ +820B
core/MoreMenu +3.5KB ⚠️ +973B
core/MultiSelector +3.2KB ⚠️ +808B
core/NumberInput +3.3KB ⚠️ +829B
core/Outline +3.3KB ⚠️ +859B
core/Pagination +3.4KB ⚠️ +823B
core/Popover +3.3KB ⚠️ +820B
core/PowerSearch +3.3KB ⚠️ +828B
core/RadioListItem +3.3KB ⚠️ +816B
core/SegmentedControlItem +3.3KB ⚠️ +866B
core/SelectableCard +3.4KB ⚠️ +852B
core/Selector +3.2KB ⚠️ +828B
core/SelectorOption +3.5KB ⚠️ +854B
core/SideNav +3.3KB ⚠️ +833B
core/SideNavCollapseButton +3.4KB ⚠️ +821B
core/SideNavHeading +3.3KB ⚠️ +825B
core/SideNavItem +3.3KB ⚠️ +828B
core/Step +3.3KB ⚠️ +833B
core/Stepper +3.4KB ⚠️ +821B
core/Switch +3.3KB ⚠️ +821B
core/Tab +3.3KB ⚠️ +842B
core/TabMenu +3.3KB ⚠️ +818B
core/Table +3.4KB ⚠️ +973B
core/TableCell +3.3KB ⚠️ +975B
core/TableHeaderCell +3.3KB ⚠️ +976B
core/TableSelectionToolbar +3.3KB ⚠️ +827B
core/TextInput +3.3KB ⚠️ +826B
core/Thumbnail +3.4KB ⚠️ +807B
core/TimeInput +3.3KB ⚠️ +831B
core/Toast +3.4KB ⚠️ +820B
core/ToggleButton +3.4KB ⚠️ +819B
core/Token +3.3KB ⚠️ +851B
core/Tokenizer +3.4KB ⚠️ +822B
core/TopNav +3.3KB ⚠️ +829B
core/TopNavHeading +3.3KB ⚠️ +821B
core/TopNavItem +3.3KB ⚠️ +869B
core/TopNavMegaMenu +3.3KB ⚠️ +833B
core/TopNavMegaMenuItem +3.3KB ⚠️ +866B
core/TopNavMenu +3.3KB ⚠️ +828B
core/TreeList +3.6KB ⚠️ +847B
core/Typeahead +3.4KB ⚠️ +816B

Bundle Size Summary

Gzip figures measure each package's entry file, not the code an import pulls in.

Package Entry (ESM) Entry gzip before Entry gzip after Delta
@astryxdesign/core 4.9KB 1.2KB 1.2KB 0B
Package stylesheet Gzip before Gzip after Delta
@astryxdesign/core 33.7KB 34.7KB +1008B

Accessibility Audit

Status: 7 accessibility violation(s) found — 7 serious.

Button pattern - 1 issue(s)
  • 🟠 serious: Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
    • Rule: color-contrast · Affects 1/10 stories · Learn more
    • WCAG: 1.4.3 (Level AA)
Checkbox pattern - 1 issue(s)
  • 🟠 serious: Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
    • Rule: color-contrast · Affects 1/8 stories · Learn more
    • WCAG: 1.4.3 (Level AA)
ClickableCard - 1 issue(s)
  • 🟠 serious: Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
    • Rule: color-contrast · Affects 1/5 stories · Learn more
    • WCAG: 1.4.3 (Level AA)
Radio group pattern - 1 issue(s)
  • 🟠 serious: Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
    • Rule: color-contrast · Affects 3/16 stories · Learn more
    • WCAG: 1.4.3 (Level AA)
RadioList - 1 issue(s)
  • 🟠 serious: Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
    • Rule: color-contrast · Affects 3/14 stories · Learn more
    • WCAG: 1.4.3 (Level AA)
SelectableCard - 1 issue(s)
  • 🟠 serious: Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
    • Rule: color-contrast · Affects 1/4 stories · Learn more
    • WCAG: 1.4.3 (Level AA)
Thumbnail - 1 issue(s)
  • 🟠 serious: Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
    • Rule: color-contrast · Affects 1/12 stories · Learn more
    • WCAG: 1.4.3 (Level AA)

Visual Regression

48 of 504 shot(s) changed.

A change here is a question, not a failure: check whether the after is the
picture you intended. Record that review on the PR. Baseline maintenance is an
explicit dispatch of CI; this report never rewrites the baseline or adds a release gate.

component story theme mode pixels
Selector Indicator Space Bottom Sheet Narrow End RTL neutral light 753,933
Selector Indicator Space Bottom Sheet Wide Start neutral light 740,072
RichTextEditor Markdown parity: side by side probe dark 556,900
RichTextEditor Markdown parity: side by side probe light 538,816
Chat Full AI Chat probe light 230,823
Chat Full AI Chat probe dark 229,805
AppShell With Mobile Nav probe light 217,010
AppShell With Mobile Nav probe dark 216,960
Collapsible Dividers probe dark 66,445
Collapsible Dividers probe light 66,445
AppShell Playground neutral dark 65,198
AppShell Playground neutral light 63,788
Chat Default neutral dark 36,304
Chat Default neutral light 35,767
Chat Empty State probe light 23,531
Chat Empty State probe dark 22,622
ChatAutoScroll Scroll Behavior Comparison neutral dark 15,378
ChatAutoScroll Scroll Behavior Comparison neutral light 14,107
Chat With Attachments probe light 13,406
Chat With Attachments probe dark 11,232

and 28 more.


Generated by PR Enrichment workflow | Storybook | Sandbox | View full report

vjeux and others added 7 commits October 25, 2026 18:18
Her arena work (the touch depth, a view's delivery only to involved
recognizers, the reset count, touchBeganElsewhere's delivery, the
simultaneity rule) reaches the recognizer's plumbing through the internal
view, as this PR keeps it out of the public type; the new
deliverBeganElsewhere joins that view.
…lved, main) into the gesture hook fixes

# Conflicts:
#	packages/core/src/gestures/GestureArena.ts
#	packages/core/src/gestures/GestureRecognizer.ts
Her foundation fixes for the review items this PR also answered take her
form: the swipe's segment reading with directions ruled out for good, the
tap's lift centroid, the claim release that counts a recognized discrete
gesture, Hover's restart and the idle recognizer's comment. Both sides'
tests stay: her spacing, 40-degree, re-basing and settling cases beside
this PR's 20-degree, re-based release and mid-hover cases.

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

This can't be approved yet: the diff rewrites component:Button FR15 from a 200 ms touch release to spec:AST-094's 250 ms control clock, which no current spec states. An engineering owner needs to approve that rewording by commenting /approve-spec with this pull request's full head SHA (the author can, as an engineering owner), or say the touch release keeps 200 ms. Separately, these fixes are needed:

  • Rebase once the prerequisite pull requests land, so the diff holds this pull request's three commits instead of 44,982 authored lines.
  • The touch press release plays fixed 250 ms and 200 ms constants, so a theme's timing.press.buttonReleaseMs, highlightOutMs or highlightOutCurve, which defineTheme accepts, never reaches it (spec:AST-094 FR4).
  • The divider rule and holdSelection key only on a coarse primary pointer, so a mouse or trackpad press on a tablet hides the dividers and holds the row; key them on a finger's press, test it, and add fine-pointer before-and-after evidence for rows (spec:AST-017 FR59).
  • gesture-press-tracking.md still announces the delegated press this pull request removes, and the selection lock cites a spec:AST-094 FR41 the record does not have.

[Automated review]

// after a cancel. With a mouse the dividers stay drawn.
borderBlockEndColor: {
default: colorVars['--color-border'],
'@media (pointer: coarse)': {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

On a touch-first device a mouse or trackpad press also writes data-astryx-press="on" (pressButton in utils/pressFeedback.ts, reached whenever stylesheetDroppedActive() is true), and these arms key only on the coarse primary pointer. So a trackpad press on a tablet hides both dividers, although the comment above says they stay drawn with a mouse (spec:AST-017 FR59). Could they key on a finger's press, with a dividers test of a mouse press under a coarse primary pointer?

);
if (
row == null ||
!isTouch(row.ownerDocument.defaultView) ||

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 checks only the device's primary pointer, so on a tablet a trackpad click that pushes from a row is held selected, while list-selection-hold.md says the hold is null with a mouse. Checking how the activation was made (or a finger marker from the press controller) would match the changeset.

* How long a control's release takes, in ms: UIButton's highlight release
* (`button.highlight.releaseMs`), for every other surface.
*/
controlReleaseMs: 250,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

timing.press.buttonReleaseMs is a registered theme motion role (motion/roleKinds.generated.ts:56), and astryx docs motion tells theme authors the code reads --motion-timing-press-button-release-ms when the motion starts, but this constant (and PRESS_PROFILES in utils/pressFeedback.ts) plays 250 ms whatever the theme sets. spec:AST-094 FR4 requires a touch motion to read its role and play no literal; the release arms could read the role variable with this value as the fallback, and the controller's clock likewise.

'@astryxdesign/core': patch
---

[chore] Internal: UIControl press tracking with control and cell profiles, the shared press paint, delegated press tracking and the gesture hooks. Not exported from the package entry point; no component uses them yet.

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 pull request removes the tracker's control and cell profiles, the gestures press paint and the delegated press tracking, so a release carrying the stack lists them beside press-machine-one-writer.md, which says they are gone. Could this entry describe only what remains?

cixzhang and others added 14 commits October 25, 2026 18:38
…o the press release

# Conflicts:
#	packages/core/src/motion/README.md
#	packages/core/src/utils/interactionOverlay.stylex.ts
#	packages/core/src/utils/pressFeedback.ts
…eme role

Both release clocks are now their roles' variables with the table's value as
fallback (timing.press.buttonReleaseMs for a control, highlightOutMs for a
cell), so the test matches them by role name instead of a bare duration.
…ePressTracker's restored option-change test) into meta#8315
meta#8356 brings F2's line on meta#8076 87796fb and main. pressFeedback.ts keeps
this branch's header, with the selection lock now at utils/selectionLock.ts;
gestures/README.md keeps the strip's press-tracker paragraph beside meta#8356's
useFingerScroll paragraph.
meta#8118 brings meta#8117's merge of meta#8076 87796fb, which meta#8356 already
carries. The merge is clean.
The press releases are their theme roles' variables with the table's value
as the fallback (var(--motion-timing-press-button-release-ms,.25s) for a
control, highlight-out-ms for a cell). build-css.test.mjs's Reduce Motion
and desktop-rule cases read a clock's fallback and find UIButton's by its
role, as pressPaintReducedMotion.test.ts does, instead of matching a bare
duration: the two that matched '.25s' found nothing and failed. Each still
fails when a Reduce Motion arm runs past 200 ms or a control's layer
release runs outside the coarse gate.
meta#8118 brings meta#8077's release clocks read through their theme motion roles
(the profile's releaseRole, read off the element when the release starts).
pressFeedback.ts keeps this branch's header and one-writer imports beside
meta#8118's role import.
…s tracker leaves

The press tracker reports control events and paints nothing, so the tests
meta#8356 added read its press another way: the per-event unit case checks only
the delivered touchDown and the browser's pan; the browser fixture's kept
press exposes its tracker, and the proof waits for keepsTouch() after the
content-touch delay, checks it still holds after the drag, then
touchUpInside at the lift.

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

This can't be approved yet: the diff rewrites current component:Button FR15 from a 200 ms touch release to a 250 ms one, and it adds holdSelection, the held list row and the divider hiding, which no current spec covers. An engineering owner needs to approve the FR15 rewording by commenting /approve-spec 036c419651e886d2ee77e38560d195d3b9310d91 on this pull request (the author can, as an engineering owner), and to name the record that governs those List changes or say they leave the stack. Separately, these fixes are needed:

  • Rebase once the prerequisite pull requests land, so the diff holds this pull request's commits (about 1,600 lines) instead of 43,965 authored lines, and resolve the conflicts with main in four motion/uikit files.
  • Read timing.curves.move in the control release (interactionOverlay.stylex.ts:263), and make timing.press.flashMs and timing.press.highlightInMs reach the press or stop registering them (spec:AST-094 FR4).
  • Key the divider hiding and holdSelection on a finger's press, so a trackpad press on a tablet keeps the dividers and holds nothing, as the changesets say (spec:AST-017 FR59).
  • Drop the perEventPointer press-tracker carve-out, which current FR19 doesn't grant, and update gesture-press-tracking.md, which still announces the pieces this pull request removes.

[Automated review]

* A control's release curve: UIButton's, UIKit's easeInEaseOut
* (`button.highlight.releaseCurve`).
*/
const CONTROL_RELEASE_EASE = pressConsts.controlReleaseEase;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The button table names timing.curves.move as UIButton's release curve, but this plays the literal, so a theme's curves: {'timing.curves.move': ...} never reaches the control release. With --motion-timing-curves-move: cubic-bezier(0, 0, 1, 1) on the root, Button's ::before still released on cubic-bezier(0.42, 0, 0.58, 1), while the duration role did reach it. spec:AST-094 FR4 asks for the role: var(--motion-timing-curves-move, cubic-bezier(0.42, 0, 0.58, 1)), as the cell release already does with its own curve role.

// Motion fade, which no theme may lengthen (design:reduced-motion DR4);
// and the keyboard's own timing, which motion in step with the keyboard
// rides (spec:AST-094 FR4).
exclude: [

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

press.flashMs and press.highlightInMs are not excluded here, so they become theme roles that astryx docs motion lists and defineTheme accepts. Nothing reads --motion-timing-press-flash-ms or --motion-timing-press-highlight-in-ms, though: the quick-tap flash runs PRESS_FLASH_MS (100 ms) in utils/pressGesture.ts. Either read the flash role in the controller's timerMs the way the fade does, or exclude both here if they are not motion (spec:AST-094 FR4).

// fading. A selection hold (the row kept selected through a navigation
// push) hides them the same way until its deselect begins, and again
// after a cancel. With a mouse the dividers stay drawn.
borderBlockEndColor: {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

On a device whose primary pointer is coarse, the controller also paints a mouse or trackpad press (pressButton in utils/pressFeedback.ts), and these arms key only on (pointer: coarse), so a trackpad press on a tablet hides both dividers. In phone emulation, a mouse press on the second row of the compact divided list turned both dividers rgba(0, 0, 0, 0). The comment above and list-dividers-hide-on-press.md say they stay drawn with a mouse, and spec:AST-017 FR59 asks for a named reason and fine-pointer evidence. Could this key on a finger's press, with a test of a mouse press under a coarse primary pointer?

);
if (
row == null ||
!isTouch(row.ownerDocument.defaultView) ||

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 checks only the device's primary pointer, so on a tablet a trackpad click that pushes from a row holds it selected, while list-selection-hold.md says the hold is null with a mouse (spec:AST-017 FR59). Checking how the activation was made, through the event's pointerType or a finger marker from the press controller, would match the changeset.

PressTrackerOptions,
'getBounds' | 'view'
> & {
/**

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

After this pull request the tracker paints nothing, so the reason given here ("The control paints press feedback per event") no longer holds. A tracker attached with perEventPointer still takes the host's listeners on a fine primary pointer, which current spec:AST-094 FR19 grants only to spec:AST-057's row swipe. No component uses it yet; could press consumers drop the option, keeping it for recognizers?

'@astryxdesign/core': patch
---

[chore] Internal: UIControl press tracking with control and cell profiles, the shared press paint, delegated press tracking and the gesture hooks. Not exported from the package entry point; no component uses them yet.

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 pull request removes the tracker's control and cell profiles, the shared press paint and the delegated press tracking, so a release that carries the stack would list them beside press-machine-one-writer.md, which says they are gone. Could this entry describe only what remains?

vjeux added a commit to vjeux/astryx that referenced this pull request Oct 26, 2026
…listener; meta#8379's press convergence) into meta#8076

The press tracker test's Button helper takes both sides' options: this
branch's cancelTravel and isBraking, and meta#8073's isDisabled.
cixzhang added a commit to vjeux/astryx that referenced this pull request Oct 26, 2026
…nothing uses

With the delegated press folded into utils/pressFeedback.ts, nothing adds a
delegated consumer type: the host's addDelegatedConsumer, its attribute walk
on the hit path and the DelegatedConsumerType export go (meta#8379's c2cd820,
reapplied at this layer).

Co-authored-by: Christopher Chedeau <vjeux@users.noreply.github.com>
vjeux added a commit to vjeux/astryx that referenced this pull request Oct 26, 2026
…e short

From the press convergence (meta#8379, superseded): with one writer of the
press attribute, any write ends a fade another painter left running, so a
press released while it runs fades on its own clock. The test fails when
writePress leaves that fade running. The ButtonPress interaction spec's
header names the press feedback instead of the removed delegated press.
@vjeux

vjeux commented Oct 26, 2026

Copy link
Copy Markdown
Contributor Author

Closing as superseded. This PR's press convergence (one writer of the press attribute in utils/pressFeedback.ts, with the delegated press removed) landed in #8073, the gesture host's part now comes from #8073 too, and the press tracker's part is held until the controls that paint through it move to the press feedback. Its two leftovers, a stale comment in the ButtonPress interaction spec and one unit test, move to #8118.

@vjeux vjeux closed this Oct 26, 2026
@vjeux
vjeux deleted the uikit/c01-press-converge branch October 26, 2026 14:07

This branch was successfully deployed

1 active deployment
Preview — 036c4196 Deployed Oct 26, 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. needs:design-review Affects visuals — Design should review needs:spec-owner-review Current knowledge records await owner approval

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants