Repository navigation
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
AI review status for this pull request.
|
PR Analysis Report📚 Storybook Preview🧪 Sandbox PreviewModified ComponentsProgressBar (@astryxdesign/core) · View in Storybook
Component Size
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. Bundle Size SummaryGzip figures measure each package's entry file, not the code an import pulls in.
Accessibility AuditStatus: 2 accessibility violation(s) found — 2 serious. ProgressBar - 1 issue(s)
Progressbar - 1 issue(s)
Visual Regression55 of 504 shot(s) changed. A change here is a question, not a failure: check whether the after is the
and 35 more. Generated by PR Enrichment workflow | Storybook | Sandbox | View full report |
There was a problem hiding this comment.
This ProgressBar touch change needs an engineering-owner decision before it can be approved: it rests only on the draft spec:AST-094, so an engineering owner, the author included, can record approval of that direction (the touch indeterminate sweep, its Reduce Motion pulse and its timing outside the theme's motion tokens) by commenting /approve-spec <full head SHA>, or point to another governing spec. Whatever that decision, two changes are needed:
- Land the stacked predecessors first (or retarget) so this pull request carries only its own 461-line commit instead of 16,939 authored lines.
- Under a coarse pointer, a value that reverses to the one it just left animates in half the stated time (400 ms instead of 800 ms), because CSS shortens reversed transitions.
[Automated review]
| transitionProperty: 'transform', | ||
| transitionDuration: { | ||
| default: durationVars['--duration-medium'], | ||
| '@media (pointer: coarse)': 'var(--_progress-bar-duration, 0s)', |
There was a problem hiding this comment.
Under a coarse pointer, a change that reverses to the value it just left runs at half the duration written here. CSS shortens a transition that reverses to its own start value, so 10 → 90 paused at 50% and sent back to 10 runs 400 ms although --_progress-bar-duration is 800 ms (433 ms when reversed live at 52%); a retarget to any other value keeps its full duration. Keep reversals off the browser's reversing path, or document that they follow the drawn distance, and add the case to ProgressBarTouch.a11y.chromium.spec.ts.
| follows. | ||
| - **FR7 — Exits animate as UIKit's do.** A touch presentation MUST play the | ||
| exit its UIKit counterpart plays. **Proposed; pending owner review:** this | ||
| departs from the draft `spec:AST-090` FR1 (exits off by default) and FR10 |
There was a problem hiding this comment.
spec:AST-090 is not in this head or on main (it is proposed in open #8003), so FR7 asks owners to amend text that is not in the repository. Land AST-090 first, or restate FR7 against records present at the head.
6efa969 to
33a8e0f
Compare
There was a problem hiding this comment.
This ProgressBar touch change needs an engineering-owner decision before it can be approved: it rests only on the draft spec:AST-094, so an engineering owner (the author included, if they are one) can record approval of that direction (the touch sweep, its trackless Reduce Motion pulse and its timing outside the theme's motion tokens) by commenting /approve-spec <full head SHA>, or point to another governing spec. Whatever that decision, these changes are needed:
trackIndeterminatesetsdefault: null, which removes the grey track from every indeterminate ProgressBar, with a mouse too; keep the default colour in the override and test the mouse path.- Land the stacked predecessors first (or retarget) so this pull request carries only its own 500-line commit instead of 16,976 authored lines.
- Under a coarse pointer, a value that reverses to the one it just left animates in half the stated time (400 ms instead of 800 ms).
- AST-094 FR7 amends
spec:AST-090, which is not in the repository.
[Automated review]
| // fill's rules under it; the compiled CSS kept both.) | ||
| trackIndeterminate: { | ||
| backgroundColor: { | ||
| default: null, |
There was a problem hiding this comment.
stylex.props() merges by property, so this backgroundColor (a null default plus one media key) replaces track.backgroundColor whole: every indeterminate track loses --color-background-muted, with a mouse and with a finger, not only under coarse pointer plus Reduce Motion. On CI's static Storybook build of this head the Indeterminate story's track computes to rgba(0, 0, 0, 0) with a mouse, against rgb(212, 212, 212) on the base. Keeping the default in the override (default: colorVars['--color-background-muted']) and asserting the track colour on the mouse and touch-sweep paths would fix and guard it.
There was a problem hiding this comment.
This ProgressBar change needs an engineering-owner decision before it can be approved: it rests only on the draft spec:AST-094, so an engineering owner (the author included, if they are one) can record approval of that direction for the iOS bar (the quarter-track sweep, the trackless Reduce Motion pulse and its theme-retunable timing) by commenting /approve-spec <full head SHA>, or point to another governing spec. Whatever that decision, these changes are needed:
trackIndeterminatekeepsdefault: null, which removes the grey track from every indeterminate ProgressBar, with a mouse and on Android too; keep the track colour as the default and test those paths.- Land the stacked predecessors first (or retarget) so this pull request carries only its own two commits instead of 19,658 authored lines.
- The iOS gate infers the engine from
-webkit-touch-callout, whichspec:AST-013FR6 does not allow, and the themeplatformcondition is outsidespec:AST-012FR2's closed vocabulary, so each needs its record amended first or has to go. - AST-094 FR4 and DEC-1 say touch motion is not themable while the new theme motion roles retune it, the motion docs advertise roles no component reads, and FR7 amends
spec:AST-090, which is not in the repository. - On iOS a fill that reverses to its previous value runs at half its written duration,
lintandtest-node (1/4)fail on a missing@astryxdesign/clichangeset and a stale docs golden, and the description needs AST-094's writing-rubric results.
[Automated review]
| default: durationVars['--duration-medium'], | ||
| '@media (pointer: coarse)': { | ||
| '@supports (-webkit-touch-callout: none)': | ||
| 'calc(var(--_progress-bar-change, 0) * var(--motion-progress-progress-view-whole-track-ms, 1000ms))', |
There was a problem hiding this comment.
On iOS a value that reverses to the one it just left runs at half this duration: CSS shortens a transition that reverses to its own start value. With the iOS gate emulated in Chromium, 10 → 90 held halfway and sent back to 10 runs 400 ms while this computes 0.8 s; a retarget to 30 keeps its 600 ms. Keep reversals off the browser's reversing path, or document that they follow the drawn distance, and add the case to ProgressBarTouch.a11y.chromium.spec.ts.
| 'pointer', | ||
| 'contrast', | ||
| 'motion', | ||
| 'platform', |
There was a problem hiding this comment.
spec:AST-012 FR2 closes the when vocabulary to width, pointer, contrast and motion: "Future environment fields require explicit additions to this closed vocabulary." platform needs that amendment first (architecture:theme-authoring-contract also says an adaptation change preserves the fixed condition vocabulary), so it would be easier to split it out with the amendment.
| * The engine is WebKit on iOS or iPadOS: the only one that implements | ||
| * `-webkit-touch-callout`. With TOUCH_QUERY, the iOS idiom. | ||
| */ | ||
| export const IOS_SUPPORTS_QUERY = '(-webkit-touch-callout: none)'; |
There was a problem hiding this comment.
spec:AST-013 FR6: "Components detect the API or CSS capability they use rather than inferring it from a browser name. A narrow engine workaround is allowed only for a reproduced defect with a regression fixture and a review or removal condition." This query is read only to tell iOS WebKit from every other engine, so the iOS idiom built on it needs FR6's owner to rule before it ships.
| measures (0.55 for a scroll view and a sheet), and a release MUST pick its | ||
| rest point by projecting its velocity the way its UIKit counterpart does: | ||
| with a deceleration rate, or with a measured projection time. | ||
| - **FR4 — Physics are not themable in touch presentations.** A touch |
There was a problem hiding this comment.
FR4, and DEC-1's "Rejected: tuning touch motion per theme", say touch motion is not themable, but this pull request adds defineTheme({motion: {springs, durations, curves}}) and ProgressBar and Spinner read --motion-* role variables a theme can set. Bring FR4 and DEC-1 in line with the roles, or drop the roles, before owners rule on this record.
| content: [ | ||
| { | ||
| type: 'prose', | ||
| text: 'On a touch screen, sheets, alerts, menus, navigation and scrolling play the springs, durations and curves measured from iOS. Each value is a motion role named by its table path, such as `springs.sheetPresent` or `timing.curves.easeInOut`. A theme retunes a role through `motion.springs`, `motion.durations` or `motion.curves`, at its root or in an adaptation rule; a role it leaves alone keeps its measured default.', |
There was a problem hiding this comment.
This says sheets, alerts, menus, navigation and scrolling play these roles, but at this head only four roles have a consumer (the three progress.* durations in ProgressBar and progress.activityIndicator.cycleMs in Spinner), so the springs.sheetPresent example below changes nothing. Document only roles a component reads, and reject role ids no table registers instead of accepting them silently.
There was a problem hiding this comment.
Approval waits on an engineering owner's decision on draft spec:AST-094 for the iOS indeterminate bar, including its iOS engine gate, which spec:AST-013 FR6 does not allow today, and its theme-retunable timing, which the draft's own FR4 rules out. An engineering owner records that decision by commenting /approve-spec b7432c040517a75d25a5827fb880aecf97c2425b on this pull request, and the author may do so as an engineering owner.
- Restore the indeterminate track, which the
nulldefault atProgressBar.tsx:281-290removes with a mouse and on Android too. - Rebase onto the stacked predecessors so this pull request carries only its own commits, drop
when.platformor amendspec:AST-012FR2, fix the halved iOS reversal, and keep the motion docs to roles that have a reader.
[Automated review]
| // with Reduce Motion the track's own color steps aside for the pulse. | ||
| trackIndeterminate: { | ||
| backgroundColor: { | ||
| default: null, |
There was a problem hiding this comment.
This null default replaces the track's --color-background-muted on every indeterminate bar, so the track renders transparent with a mouse, on Android and on iOS without Reduce Motion (the base paints rgb(212, 212, 212)). Give both defaults the track colour and keep transparent only under the gated Reduce Motion branch, then assert the track colour on the mouse and Android paths.
| default: durationVars['--duration-medium'], | ||
| '@media (pointer: coarse)': { | ||
| '@supports (-webkit-touch-callout: none)': | ||
| 'calc(var(--_progress-bar-change, 0) * var(--motion-progress-progress-view-whole-track-ms, 1000ms))', |
There was a problem hiding this comment.
A move reversed halfway (10 to 90, back to 10 when drawn at 50%) is specified as 0.8 s here, but CSS Transitions shortens a transition that reverses to its start, so Chromium runs it in 400 ms, half what progressView.wholeTrackMs documents. Start the reversal as a fresh transition or restate the table, and add the case to the touch spec.
| * is everything else. Pair `ios` with `pointer: 'coarse'` for a touch | ||
| * profile, such as touch motion tuned per platform. | ||
| */ | ||
| platform?: 'ios' | 'other'; |
There was a problem hiding this comment.
spec:AST-012 FR2 closes the when vocabulary to width, pointer, contrast and motion and says future fields need explicit additions to it; no theme in the repository sets platform, only the motion doc's example. Remove it, or amend AST-012 FR2 in its own pull request.
| * The engine is WebKit on iOS or iPadOS: the only one that implements | ||
| * `-webkit-touch-callout`. With TOUCH_QUERY, the iOS idiom. | ||
| */ | ||
| export const IOS_SUPPORTS_QUERY = '(-webkit-touch-callout: none)'; |
There was a problem hiding this comment.
This query identifies the engine to choose a presentation; spec:AST-013 FR6 allows an engine test only as a workaround for a reproduced defect with a regression fixture and a removal condition, so it needs an owner decision: amend FR6, or key the presentation on a capability.
| content: [ | ||
| { | ||
| type: 'prose', | ||
| text: 'On a touch screen, sheets, alerts, menus, navigation and scrolling play the springs, durations and curves measured from iOS. Each value is a motion role named by its table path, such as `springs.sheetPresent` or `timing.curves.easeInOut`. A theme retunes a role through `motion.springs`, `motion.durations` or `motion.curves`, at its root or in an adaptation rule; a role it leaves alone keeps its measured default.', |
There was a problem hiding this comment.
At this head only the three ProgressBar durations and Spinner's cycle read a motion role, so sheets, alerts, menus, navigation and scrolling do not follow these roles yet, and the example's springs.sheetPresent and springs.navigationPush change nothing. Document only roles that have a reader, or mark the rest as not yet in use.
There was a problem hiding this comment.
Approval waits on an engineering owner's decision about draft AST-094. That decision covers the iOS-only engine gate (current AST-013 FR6 does not allow it), the trackless Reduce Motion pulse, and theme-retunable touch roles, which AST-094 FR4 and DEC-1 forbid as written. An engineering owner records it by commenting /approve-spec <full head SHA> on this pull request, and you may do so yourself if you are an engineering owner. Whatever the decision, these still need changes:
- With Reduce Motion on iOS the pulsing bar reaches only 1.52:1 to 2.42:1 against the page, below the 3:1 non-text contrast AST-020 requires.
- Rebase onto the stacked predecessors so the pull request carries only its own four commits, about 640 of its 19,658 authored lines.
- Drop
when.platformor amend AST-012 FR2 first, derive the Spinner spoke delays from the cycle role, keep a reversed iOS move at its documented duration, document only motion roles something reads, and fix the citation of the missing AST-090.
[Automated review]
| '@media (pointer: coarse)': { | ||
| '@supports (-webkit-touch-callout: none)': { | ||
| default: colorVars['--color-background-muted'], | ||
| '@media (prefers-reduced-motion: reduce)': 'transparent', |
There was a problem hiding this comment.
With Reduce Motion on iOS this removes the track, so the pulsing fill (accent at 0.3 to 0.6 opacity) reaches only 1.52:1 to 2.42:1 against the light page, below the 3:1 non-text contrast that AST-020 requires for a meaningful state graphic. Pulsing at 0.74 opacity or more, or keeping the track and the 3 s slide that a mouse and Android keep, would hold 3:1.
| default: durationVars['--duration-medium'], | ||
| '@media (pointer: coarse)': { | ||
| '@supports (-webkit-touch-callout: none)': | ||
| 'calc(var(--_progress-bar-change, 0) * var(--motion-progress-progress-view-whole-track-ms, 1000ms))', |
There was a problem hiding this comment.
A move sent back to its starting value runs at half this duration, because CSS shortens a transition that reverses to its start. With the iOS gate emulated, 10 → 90 takes 800 ms; sent back to 10 halfway, it takes 400 ms, while 90 → 30 from the same point takes the documented 600 ms. A reversal test, plus a path the reversing rule does not shorten (or a documented exception in progress.ts), would close this.
| // spoke partway through its cycle, so every spoke is in step from the first | ||
| // frame. | ||
| const spokeStyles = stylex.create({ | ||
| s0: {animationDelay: '-600ms'}, |
There was a problem hiding this comment.
These delays are sized for the 800 ms default, but the duration reads --motion-progress-activity-indicator-cycle-ms, which themes are invited to retune. At 1600 ms the bright head sits on one spoke for 800 ms and then steps 0, 7, 0, 1…. Deriving each delay from the same variable, for example calc(var(--motion-progress-activity-indicator-cycle-ms, 800ms) * -6 / 8) here, keeps the order at any cycle.
| * is everything else. Pair `ios` with `pointer: 'coarse'` for a touch | ||
| * profile, such as touch motion tuned per platform. | ||
| */ | ||
| platform?: 'ios' | 'other'; |
There was a problem hiding this comment.
AST-012 FR2 closes the condition vocabulary to width, pointer, contrast and motion, and says future environment fields need an explicit addition to it. This adds platform without amending FR2, and nothing in this pull request reads it. Dropping it here, or amending AST-012 first, resolves the contradiction.
| * The engine is WebKit on iOS or iPadOS: the only one that implements | ||
| * `-webkit-touch-callout`. With TOUCH_QUERY, the iOS idiom. | ||
| */ | ||
| export const IOS_SUPPORTS_QUERY = '(-webkit-touch-callout: none)'; |
There was a problem hiding this comment.
AST-013 FR6 asks components to detect the capability they use rather than infer the engine, and allows an engine workaround only for a reproduced defect with a regression fixture and a removal condition. Here the property identifies iOS WebKit in order to choose a presentation, so it needs an engineering owner's decision (AST-094 approved together with an FR6 amendment) before it can land.
| ); | ||
| } | ||
| const registered = motionRole(id); | ||
| if (registered !== undefined && registered.kind !== kind) { |
There was a problem hiding this comment.
A well-formed id that names no registered role passes this check and writes a variable nothing reads; the error text even suggests sheet.present, which no table registers. Rejecting unregistered ids would catch a theme author's typo.
| content: [ | ||
| { | ||
| type: 'prose', | ||
| text: 'On a touch screen, sheets, alerts, menus, navigation and scrolling play the springs, durations and curves measured from iOS. Each value is a motion role named by its table path, such as `springs.sheetPresent` or `timing.curves.easeInOut`. A theme retunes a role through `motion.springs`, `motion.durations` or `motion.curves`, at its root or in an adaptation rule; a role it leaves alone keeps its measured default.', |
There was a problem hiding this comment.
Only four of the 50 roles have a reader in this pull request: three in ProgressBar and one in Spinner. Sheets, alerts, menus, navigation and scrolling do not play these roles yet, so this sentence and the example's springs.sheetPresent and springs.navigationPush promise effects a theme will not see.
…ers change at once (#8272) ## Exact decision needed What a person who prefers reduced motion sees when a core component animates a change, on touch and on other pointers, and whether a component may keep its motion. ## Existing authority searched - `design:motion` DR5 (draft): every animated transition has an immediate or minimally moving form. Draft, so not authority. - `spec:AST-013` FR13: reduced-motion behavior is unchanged by server-rendered entrances; it defines none. - `spec:AST-012` FR2: `motion: reduce` and `pointer: coarse/fine` are the adaptation conditions. - No current web record defines component behavior under reduced motion. - Search terms: reduced motion, prefers-reduced-motion, cross-fade, Reduce Motion, motion DR5, spring, travel. Overlapping open pull requests: #7367 (draft `design:motion` DEC-2, hover entrances; no reduced-motion rule), #8214 (layer fade under a finger with Reduce Motion; conforms once its fade is 200 ms or less), #8052 (AST-094 FR8 carries the matching touch rule), #8211, #8239, #8253 (touch indicator and placeholder work; continuous indicators are outside this record). ## Decision New current record `design:reduced-motion`, matching iOS Reduce Motion with Prefer Cross-Fade: - DR1: under `prefers-reduced-motion: reduce`, a core component's entrances, exits, presentation switches, and state changes never move, scale, resize, or spring. - DR2: on a coarse pointer, they cross-fade: opacity only, 200 ms or less. - DR3: on any other pointer, they complete at once. - DR4: no core component, prop, or theme value keeps motion under reduced motion. `spec:AST-057` FR5 names that a swiped row's slide out, spring back, and hold-out follow DR2 under reduced motion. The draft `design:motion` keeps its other rules unapproved; its DR5 points to the new record. A separate record keeps the promotion to this one rule, as `docs/design/README.md` advises for a different approval lifecycle. ## Rejected alternatives - A per-component setting that keeps full motion under reduced motion. ## Claim scope and non-goals Only transitions under reduced motion. Motion without the preference, durations and easing, tokens, continuous indicators such as a spinner, and content the person drags with their own finger are outside this record. ## Evidence and implementation relationship Layers that open under a finger with Reduce Motion appear in one frame today, where iOS cross-fades. The open fix #8214 makes them fade under a coarse pointer and stay immediate under a mouse, which conforms to DR2 and DR3 once its fade is 200 ms or less. The open draft #7367 (`design:motion` DEC-2, hover-summoned layers) does not touch reduced motion. The AST-094 revision in #8052 carries the matching touch rule. No implementation is included. ## Writing rubric results - R1 narration: none. - R2 research in the record: none. - R3 evidence naming a change: none; verification names browser states. - R4 rejected alternatives over one line or outside a decision: one, inside DEC-1, one line. - R5 pull request or issue references remaining: none. - 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`
|
Posted by Cindy's agent on her behalf. Parts of this PR re-implement behavior that already exists, or is being specified, as a shared part of core. Converging keeps one implementation per behavior:
This is about where the behavior lives, not about the PR's intent. |
|
Agreed: one implementation.
|
There was a problem hiding this comment.
Approval needs an engineering owner to approve or identify the governing spec for the iOS Safari look of ProgressBar's indeterminate bar, which today rests only on draft spec:AST-094: a 25% linear sweep, a Reduce Motion pulse with no track, whether it applies on iOS only or on every touch screen, and whether themes may retune its timing. An engineering owner records that decision by commenting /approve-spec <full head SHA> on this pull request, and the author may do so as an engineering owner. Whatever that decision, please rebase onto the landed stack so this diff is the ProgressBar change alone, and fix these:
- Use the shared compact definition from
spec:AST-012FR9 instead of 744 px, which opens adaptive menus as popovers on 744–767 px touch screens. - Key the touch styles on the shared touch resolver instead of
-webkit-touch-callout, asspec:AST-013FR6 and the owner comment ask. - Drop
when.platform, the theme-settable reduced-motion fade andreducedMotion: 'keep', whichspec:AST-012FR2 and the reduced-motion design record rule out. - Make the motion docs describe only roles a component reads, reject unknown role ids, and fix AST-094's citation of the missing AST-090.
[Automated review]
| export const TOUCH_QUERY = '(pointer: coarse)'; | ||
|
|
||
| /** The viewport is compact: layout behaviours. */ | ||
| export const COMPACT_QUERY = '(width < 744px), (height < 500px)'; |
There was a problem hiding this comment.
spec:AST-012 FR9 makes a screen compact below the effective md point (768 px by default) and says no resolver keeps size numbers of its own; on a 750 px touch screen this opens adaptive menus as popovers. main exports compactDefinition() / DEFAULT_COMPACT_DEFINITION for this.
| * The engine is WebKit on iOS or iPadOS: the only one that implements | ||
| * `-webkit-touch-callout`. With TOUCH_QUERY, the iOS idiom. | ||
| */ | ||
| export const IOS_SUPPORTS_QUERY = '(-webkit-touch-callout: none)'; |
There was a problem hiding this comment.
-webkit-touch-callout stands in for "iOS" here, which spec:AST-013 FR6 allows only for a reproduced engine defect with a fixture and a removal condition; the engineering owner asked for the shared touch key instead.
| * is everything else. Pair `ios` with `pointer: 'coarse'` for a touch | ||
| * profile, such as touch motion tuned per platform. | ||
| */ | ||
| platform?: 'ios' | 'other'; |
There was a problem hiding this comment.
platform is not in spec:AST-012 FR2's closed when vocabulary (width, height, pointer, contrast, motion), which requires an explicit addition to the record first.
| * Cross-Fade Transitions on (opacity CABasicAnimation 0.5 s, | ||
| * (0.42, 0, 0.58, 1)), Oct 23 2026 | ||
| */ | ||
| reducedMotionCrossFadeMs: 500, |
There was a problem hiding this comment.
As a theme role this lets a theme lengthen the reduced-motion fade, and its 500 ms default exceeds the 200 ms design:reduced-motion DR2 allows on touch; DR4 says theme values offer no way to keep a longer animation under reduced motion.
| `${location}: a motion role is named by its table path, such as "sheet.present" or "springs.navigationPush".`, | ||
| ); | ||
| } | ||
| const registered = motionRole(id); |
There was a problem hiding this comment.
An id the registry does not know passes through and emits a variable nothing reads (the test expects 'sheet.present' to become --motion-sheet-present), so a typo in a theme fails silently.
| content: [ | ||
| { | ||
| type: 'prose', | ||
| text: 'On a touch screen, sheets, alerts, menus, navigation and scrolling play the springs, durations and curves measured from iOS. Each value is a motion role named by its table path, such as `springs.sheetPresent` or `timing.curves.easeInOut`. A theme retunes a role through `motion.springs`, `motion.durations` or `motion.curves`, at its root or in an adaptation rule; a role it leaves alone keeps its measured default.', |
There was a problem hiding this comment.
At this head only ProgressBar and Spinner read a --motion-* variable and no component calls the animator, so retuning springs.sheetPresent or springs.navigationPush as the example shows changes nothing.
| follows. | ||
| - **FR7 — Exits animate as UIKit's do.** A touch presentation MUST play the | ||
| exit its UIKit counterpart plays. **Proposed; pending owner review:** this | ||
| departs from the draft `spec:AST-090` FR1 (exits off by default) and FR10 |
There was a problem hiding this comment.
spec:AST-090 is not on main or in this pull request, so this amendment cannot be checked.
…(spec:AST-094 FR18, DEC-13) A screen-edge pan attached to a stack container, as wide as the screen, with a touch 4 px from its edge: inside the 40.2 px band the pan decides at UIKit's 15 px whatever the element's width, and then tracks the travel past it. From several edges too. Both fail while a wider element decides at FR19's 10 px.
…'s width (spec:AST-094 FR18, DEC-13) FR18: inside the 40.2 px band a screen-edge pan decides at UIKit's 15 px screen-edge hysteresis; outside it the author's scrolling is untouched and FR19's 10 px governs every other claim. The pan decided at 10 px on any element wider than the band, so NavigationStack's edge pan, attached to the stack container, began 5 px early. The edge zone still decides only the touch-action; a touch outside every band still fails at once. The two cases that pinned the 10 px decision go.
…er's move keeps that finger until it lifts) into the experimental touch exports
…than the band (spec:AST-094 FR18, DEC-22) FR18 as amended in meta#8631 (DEC-22): the band's pan-x claim and 15 px start hold only where the screen-edge pan is attached to an element within the band; on an element that reaches beyond it, whose touch-action cannot claim per touch, a touch in the band decides at FR19's 10 px like every other claim. This restores the 10 px decision 3d85c30 removed and keeps 15 px on an element within the band. The cases pin DEC-22 both ways (a wide element with a touch at x=4 begins at 10, an in-band strip at 15, and from several edges at 10 on a wide element); the 10 px cases fail on 3d85c30.
…xperimental touch exports The motion README's Files table is the union: main's rows, with meta#8663's resolveSnapPoint.ts and selectPage.ts, plus this branch's, in main's order. # Conflicts: # packages/core/src/motion/README.md
The gesture README promises that usePressTracker rebuilds its tracker when trackingExpansion, highlightDelay, cancelTravel or quickTapFlash change, from the next touch. That fix (c248459) was lost in a later merge of the press-tracking line: the tracker was built once, so a changed option never applied. It is memoized on those four again; the node attachment, keyed on the tracker, moves to the new one and disposes the old. The callbacks keep being read through the ref on every touch. The new test fails before this change (the same tracker after each option change) and passes after it.
There was a problem hiding this comment.
Approval is on hold until an engineering owner settles the governing spec for ProgressBar's indeterminate bar under a finger: no current record states Safari's 25% linear sweep, the trackless 0.74 to 1.0 Reduce Motion pulse, or whether spec:AST-094 FR4 needs motion roles for their timing. An engineering owner records that decision by commenting /approve-spec <full head SHA> on this pull request, and the author may do so as an engineering owner. Whatever that decision, these changes are still needed:
- Land #8225 and its parents first, or retarget onto #8225, so this diff is its own 699 lines rather than 18,847.
- Key the touch sweep on
:dir(rtl)(ProgressBar.tsx:438), because a left-to-right bar inside a right-to-left page is empty for two thirds of each cycle. - Attach real-device iOS Safari and Android Chrome recordings for the touch claims.
[Automated review]
| ':is([dir="rtl"] *)': indeterminateSlideRtl, | ||
| '@media (pointer: coarse)': { | ||
| default: touchSweep, | ||
| ':is([dir="rtl"] *)': touchSweepRtl, |
There was a problem hiding this comment.
This key matches any right-to-left ancestor, while the 25% segment sits at the start of its own region, so a left-to-right bar inside a right-to-left page sweeps left off the track: on a 370 px track 92.5, 57.8, 23.1 and 0 px are visible at 0, 125, 250 and 500 ms, and the bar is empty from 333 to 1,667 ms of each 2 s cycle. design:bidirectionality DR3 asks ordered progression to follow the containing region's direction. Keying the sweep on ':dir(rtl)', as the determinate fill does at lines 356 and 369, fixes it; a left-to-right-inside-right-to-left case like the one in ProgressBarMotion.a11y.chromium.spec.ts would keep it fixed.
| sweep: '1000ms', | ||
| /** Under Reduce Motion, each direction of Safari's pulse instead. */ | ||
| reducedMotionPulse: '1000ms', | ||
| /** The curve of all three: linear. */ | ||
| easing: 'linear', |
There was a problem hiding this comment.
These are literals played in place of motion roles. spec:AST-094 FR4 says every duration and curve a touch presentation plays MUST be a motion role named for its use and that a component MUST NOT play a literal, and registerProgressBarTable() registers progress with no roles. Unless an engineering owner rules otherwise on the open question, name the sweep, the pulse and the linear curve as roles in the generated table (DEC-5) and read them here.
… s of wall clock
The two proofs that a Reduce Motion dip held before its first frame
still lands (after the hold is finished, and after it is resumed) polled
the box for 2 s of wall clock. On a loaded machine the page's main
thread ran the dip's next step late and the poll ran out first: one
WebKit run read {opacity: 0, translate: 'none'} with four WebKit
containers on the box, then passed in 530 ms on a rerun. They now wait
until the box runs no animation, on the animations' own finished
promises (including the fade back in the dip starts when its fade out
ends), and then assert the landed state. The test's own timeout still
bounds them.
With a 2.5 s main-thread block induced right after the release, both
proofs failed before this change (Timeout 2000ms exceeded while waiting
on the predicate) and pass after, 3 runs each in Chromium.
Main merged meta#8045 and meta#8046. The one conflict is utils/pressFeedback.ts: it takes main's merged meta#8046 text (the finger and button slots, the mouse and key press) and keeps this pull request's own additions, the one writer of the press attribute (writePress, paintPress, readPressPaint) and the header line naming them.
# Conflicts: # internal/interaction-harness/README.md # internal/interaction-harness/src/busy.test.ts # internal/interaction-harness/src/busy.ts # internal/interaction-harness/src/frames.ts # internal/interaction-harness/src/harness.interaction.browser.spec.ts
Main's button slot, merged with meta#8046, ends a press's release at once when the next press starts, by clearing the press attribute directly. On a row another painter holds, that clear erased the hold, which this pull request's one writer refuses. A mouse press on a held row, released, then a press elsewhere must leave the row held. Fails until the early end goes through the one writer.
finish() writes none through writePress, as this pull request's controller paints, so a held row stays its owner's when the next press ends a release early, under the finger and the button slots alike.
Both upstream heads are folded onto main 70ea859 (her meta#8045 frame evidence and meta#8046 coarse press): meta#8446 takes main's harness files, and meta#8073 carries the press controller onto meta#8046's slots. meta#8076 has no change of its own in either set of files, so the merge takes theirs with no hand resolution, and meta#8076 is clean against main again.
jsdom serves no cross-origin sheet, so the catch around the touch tests' rule reader could only hide a real error.
…cknowledgement Each frame's acknowledgement settles before the session detaches, and a failure fails the test instead of being swallowed.
jsdom serves no cross-origin sheet, so the catch could only hide a real error.
…t screencast acknowledgement Each frame's acknowledgement settles before the session detaches, and a failure fails the test instead of being swallowed.
There was a problem hiding this comment.
Approval is on hold until an engineering owner settles the governing spec for ProgressBar's indeterminate bar under a finger: no current record states Safari's 25% linear sweep or the trackless 0.74 to 1.0 Reduce Motion pulse (spec:AST-094 leaves each component's touch presentation to its own record, and the ProgressBar record is still a draft), and the owners also need to say whether AST-094 FR4's motion roles apply to that timing. An engineering owner can record the decision by commenting /approve-spec <full head SHA> on this pull request (the author may do so as an engineering owner), name the record that should state it, or keep today's slide on touch. Whatever that decision, these changes are needed:
- Land #8225 and its parents first, or retarget onto #8225, so this diff is its own 702 lines rather than 17,109.
- Key the touch sweep on
:dir(rtl)instead of:is([dir="rtl"] *)(ProgressBar.tsx:438), because a left-to-right bar inside a right-to-left page is empty for two thirds of every cycle. - Attach recordings from a real iPhone in Safari and a real Android phone in Chrome for the touch claims, as AST-094's platform support requires.
[Automated review]
| ':is([dir="rtl"] *)': indeterminateSlideRtl, | ||
| '@media (pointer: coarse)': { | ||
| default: touchSweep, | ||
| ':is([dir="rtl"] *)': touchSweepRtl, |
There was a problem hiding this comment.
This key matches any right-to-left ancestor, while the 25% segment sits at the start of its own region, so a left-to-right bar inside a right-to-left page plays the right-to-left sweep from the left end and leaves the track: on a 370 px track 92.5, 57.8, 23.1 and 0 px of it are visible at 0, 125, 250 and 500 ms, and the track is empty from 333 to 1,667 ms of every 2 s cycle. design:bidirectionality DR3 asks ordered progression to follow the containing region's direction. Keying the sweep on ':dir(rtl)', as the determinate fill does at lines 356 and 369, fixes it; a left-to-right-inside-right-to-left case in ProgressBarTouch.a11y.chromium.spec.ts would keep it fixed.
Depends on #8225. Review only this PR's change: vjeux/astryx@bd4ecc6...9f35484
User impact
Part of making Astryx match iOS under a finger (
spec:AST-094): an indeterminate ProgressBar slides a 40% segment in an eased sweep, a desktop pattern. iOS's only indeterminate bar is Safari's valueless<progress>: a quarter of the track sweeping linearly, 1 s each way. ProgressBar now draws that on touch devices, and keeps moving on a busy page (Safari's freezes).Options and tradeoffs:
Visual authority
DDrow reused or amended.Design decisionstable by a team design owner.docs/design/.None is settled. Proposed, pending owner review: Safari's
<progress>under a finger, in the theme's colors and radius, with the brighter pulse (spec:AST-020's 3:1).Before and after
This bar (top) and Safari's

<progress>(bottom), iOS 26.2 simulator:Right to left, and Reduce Motion:

A 0.7 s busy script, without and with Reduce Motion:


Android, through a busy script:

State matrix
Size (gzip, ProgressBar's import, #8225 → head): JavaScript 9,450 → 9,554 B (+104), CSS 7,137 → 7,400 B (+263);
astryx.css35,719 → 36,013 B (+294).Scope
Testing
What I ran and what it showed:
<progress>on the iOS 26.2 simulator: the same segment and 1 s reversal; through a 0.7 s busy script, this bar moves and Safari's freezes. Android emulator: the same.