Skip to content

spec(ProgressBar): touch determinate timing and a Reduce Motion pulse - #9425

Merged
cixzhang merged 1 commit into
mainfrom
spec/progressbar-touch
Nov 2, 2026
Merged

cixzhang merged 1 commit into
mainfrom
spec/progressbar-touch

Conversation

@cixzhang

@cixzhang cixzhang commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Maintainer impact

  • People on a phone see a determinate ProgressBar move the way iOS draws it: linearly, from where the fill is drawn, at one second per whole track of change (10% to 90% takes 0.8 s). Above zero the fill is at least 16px long; at zero nothing is painted. A mouse or trackpad keeps today's eased theme timing.
  • People with Reduce Motion on, on any pointer, see an indeterminate bar that no longer travels: a full-width solid bar whose opacity pulses slowly (2 s each way, from 1 down to 0.84). Without Reduce Motion the indeterminate bar keeps today's 40% eased slide on every pointer.
  • Product teams: no prop, default or value change. Both behaviors are recorded as implementation gaps until built.
  • Contrast: at the 0.84 floor every tone that reaches 3:1 against the track at full opacity still does, in light and dark (lowest 3.01:1, success in dark). Warning and neutral in the light default theme are below 3:1 even at full opacity (1.65–2.03:1), so no opacity floor can reach 3:1 for them; that is recorded as a gap under OQ1, the open standalone-contrast treatment.

Exact decision needed

How a determinate fill moves under a coarse primary pointer, and what the indeterminate bar shows under reduced motion.

Existing authority searched

component:ProgressBar (FR4, FR6, AR1, OQ1, OQ2), component:Skeleton (FR3, FR4), spec:AST-094 (FR1, FR2, FR4, FR13, DEC-1, DEC-5, DEC-6, DEC-15), spec:AST-108 (FR2, FR3, FR4, DEC-1), design:reduced-motion (DR1–DR3, DEC-3, content boundary), design:motion, the theme duration tokens (longest is 1300 ms), and the registered motion tables. AST-094 makes native measured timing the touch default and requires named roles, but leaves each component's presentation to its own record; the reduced-motion record leaves continuous status indicators out of scope; ProgressBar OQ2 held the reduced-motion loop open. ProgressBar's record owns both decisions.

Decision

The owner ruled on 2026-11-01:

"go with proposal for determinate"
"for indeterminate, keep original animation"
"skeleton keep current"
"for indeterminate we do need a reduced motion variant"
"it should be a solid bar that slowly pulses opacity on the fill"

Changed records: component:ProgressBar only. component:Skeleton is unchanged.

  • FR4 amended: under a coarse primary pointer, the fill moves linearly from where it is drawn, for the progress.fillTrackMs role (1000 ms, UIKit's progress view for a whole-track change) times the share of the track moved; at least 16px above zero; nothing at zero. The duration and its linear curve (progress.curves.fill) are roles in the generated motion role table, and tempo scales the duration (spec:AST-094 FR4, FR13, DEC-1, DEC-5; spec:AST-108 FR3). Fine pointers unchanged; reduced motion still lands at once.
  • FR6 amended: without reduced motion, today's 40% eased slide on every pointer. Under reduced motion, on every pointer, a full-width solid fill with no segment and no travel, pulsing only its opacity between 1 and 0.84, each way on the progress.reducedMotionPulseMs role (2000 ms) and the existing timing.curves.move curve; the track is unchanged. No theme duration token is near 2 s, so the pulse is a named role; as a busy loop it is on the fixed list, so tempo does not scale it. It applies design:reduced-motion DR1's no-travel rule (an opacity change in place of travel).
  • AR4 added: the pulse floor of 0.84 and the contrast it keeps.
  • DEC-2 added; OQ2 removed (answered).
  • Current-state impact: three gaps (touch timing unbuilt; the reduced-motion slide still travels; warning and neutral below 3:1 in light).
  • Verification: pending rows for coarse vs fine pointer timing, the 16px minimum, zero, the reduced-motion pulse with no travel, and contrast at the floor in both themes.

This unblocks #8225 and the Reduce Motion part of #8239; #8239's quarter-track sweep under a finger and its 0.74–1.0 pulse are not adopted. #8253 (Skeleton) is not adopted.

Rejected alternatives

  • iOS Safari's quarter-track sweep for the indeterminate bar under a finger (the owner kept the 40% slide).
  • Keeping a slowed slide under reduced motion: it still travels.

Claim scope and non-goals

Determinate fill timing under a coarse pointer and the indeterminate bar under reduced motion only. Skeleton, the fine-pointer determinate motion, the standalone contrast treatment (OQ1) and the tone colors are unchanged.

Evidence and implementation relationship

UIKit measurement of the progress view's animated timing (whole track 1 s, linear) and minimum fill, iOS 26.2 simulator. Contrast computed from the default theme tokens: each fill at 0.84 opacity composited over --color-background-muted on the body and surface backgrounds, light and dark. No implementation in this PR.

Writing rubric results

  • R1 narration: none; the new FR4 and FR6 text, AR4, DEC-2 and the gaps are present tense about the system.
  • R2 research in the record: none; the per-tone contrast table stays here, and AR4 keeps the floor and its lowest value.
  • R3 evidence naming a change: none; the FR4 basis names the UIKit measurement and DEC-2.
  • R4 rejected alternatives over one line or outside a decision: one, in DEC-2, one line.
  • R5 pull request or issue references remaining: none in the record.
  • R6 ruled open questions still listing options: none; OQ2 is answered and removed, and OQ1 is unanswered and unchanged.

Scope

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

Validation

  • pnpm install --frozen-lockfile
  • pnpm check:knowledge: Knowledge templates and records are aligned.
  • Prettier: clean
  • git diff --check: clean

@vercel

vercel Bot commented Nov 2, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated
astryx Building Building Preview Nov 2, 2026 1:44am UTC

Request Review

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

astracat-bot Bot commented Nov 2, 2026

Copy link
Copy Markdown

AI review status for this pull request.

Review status Updated
🔄 In progress (for maintainers only) Nov 2, 2026, 1:44 AM UTC

@github-actions github-actions Bot added the needs:spec-owner-review Current knowledge records await owner approval label Nov 2, 2026
@cixzhang

cixzhang commented Nov 2, 2026

Copy link
Copy Markdown
Contributor Author

/approve-spec 290c3d7

@github-actions github-actions Bot removed the needs:spec-owner-review Current knowledge records await owner approval label Nov 2, 2026
@cixzhang
cixzhang merged commit 1f6919c into main Nov 2, 2026
51 of 52 checks passed
@github-actions
github-actions Bot deleted the spec/progressbar-touch branch November 2, 2026 06:05

This branch was successfully deployed

1 active deployment
Preview — 290c3d72 Deployed Nov 2, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant