Repository navigation
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
AI review status for this pull request.
|
There was a problem hiding this comment.
This review is on hold for an owner decision. No current spec governs the touch wheel's UIPickerView look, because spec:AST-094 covers touch behavior only. An engineering or design owner needs to provide or identify the record that governs the look, its --color-neutral band fill and the INV7 exception its band copy needs, and to approve or reject the draft rest rule in component:DateInput FR13/DEC-1 and component:DateTimeInput FR8. Any engineering owner records the decision by commenting /approve-spec <full head SHA> once the head carries that record, and as an engineering owner the author can do this too. These points need fixing whatever the decision:
- Land #8366 and its predecessors first, so this diff carries only the look (about 2,960 lines instead of 42,176), then split it or show why it has to stay together.
PickerWheel.tsxdraws every label again throughcontent: attr(data-label)pseudo-elements, whicharchitecture:component-style-authoringINV7 rules out unless an owner records an exception.- A drag re-renders the wheel through
flushSynceach time it leaves the mounted rows, whichspec:AST-094FR9 rules out ("no component render per move"). - The
PickerWheel.tsxheader says the touch layer loads lazily, butWheel.tsximports it statically, and INV6 asks for the component size report for this change.
[Automated review]
| // technology meet only the options. | ||
| rowLabel: { | ||
| '::before': { | ||
| content: 'attr(data-label)', |
There was a problem hiding this comment.
This draws the label again as generated content, and stripLabel (line 257) draws it a third time, over the transparent option (line 211) that already holds it. architecture:component-style-authoring INV7 says content renders once and a pseudo-element never repeats content, and it allows an exception only as a recorded owner decision with element counts. Either record that exception where the look is approved, or draw the band and drum without repeating the label.
There was a problem hiding this comment.
The repetition is the look itself. Each label is the listbox's transparent option (for assistive technology and taps), a row on the drum, and a row in the band's magnified copy: a row crossing the band's edge is drawn both magnified and unmagnified, as UIKit draws two table views, so one rendering cannot show it. The description now asks the design owner to record the INV7 exception with the look, with the counts: 265 elements for the TimeInput sheet under a finger, 288 under a mouse.
| // A motion's animations are baked per mounted row as it starts, and | ||
| // a drag frame writes the mounted rows: both need the rows now. | ||
| // eslint-disable-next-line @eslint-react/dom-no-flush-sync, @eslint-react/set-state-in-effect -- see above; never called from an effect with `now` | ||
| flushSync(() => setRowWindow(next)); |
There was a problem hiding this comment.
The pan's began and changed handlers (lines 707 and 720) call this with now, so every time the offset leaves the mounted window, about every two rows, the whole column renders synchronously inside a touch move. spec:AST-094 FR9 requires no component render per move. Recycling the mounted drum and strip nodes inside WheelMotion on the drag path would move the window without a render.
There was a problem hiding this comment.
Agreed, a real gap: the mounted window is React state, so a drag that leaves it renders the column inside a touch move. The fix is to recycle the mounted drum and strip nodes imperatively in WheelMotion, so the drag path never renders. It lands once the design owner rules on this look; the description lists it as a known issue until then.
| * programmatic turns | ||
| * @output Exports PickerWheel — one UIPickerView column | ||
| * @position Internal component; the Wheel under a finger (Wheel.tsx picks | ||
| * it and loads it lazily), drawn standalone or inside a WheelGroup |
There was a problem hiding this comment.
Wheel.tsx imports PickerWheel statically (line 73), so the touch layer is not loaded lazily. Please correct this comment; INV6 then asks for the size report, and a justification if the touch layer is flagged.
There was a problem hiding this comment.
Fixed in b84acba: the header says Wheel.tsx imports PickerWheel statically. The description now gives INV6's size report for this pull request against #8366: +0.3 KB gzip JavaScript and +0.3–0.4 KB CSS each for DateInput, TimeInput and DateTimeInput (DateInput 118.8 → 119.1 KB), under INV6's 2 KB and 1 KB flags.
There was a problem hiding this comment.
This review is on hold for an owner decision: no current spec governs the touch wheel's UIPickerView look, since spec:AST-094 covers touch behavior only, and the head also adds the draft rest rule in component:DateInput FR13/DEC-1 and component:DateTimeInput FR8. An engineering or design owner needs to provide or identify the record that governs the look, its --color-neutral band fill and the INV7 exception its band copy needs, and to approve or reject the rest rule; any engineering owner, the author included, records that decision by commenting /approve-spec <full head SHA> once the head carries that record. Whatever the decision, these points need changes:
- Land #8366 and its predecessors first, so this diff carries only the look (2,999 authored lines instead of 37,149), then split it or show why it has to stay together.
- On short lists a finger now renders more elements than a mouse (1,031 against 1,012 on
BottomSheetNarrowRangewith the month and year wheels open), past the 5 thatspec:AST-017FR60 allows, so trim the touch wheel's fixed nodes or include these counts in the INV7 exception. - A drag still re-renders the wheel through
flushSynceach time it leaves the mounted rows (PickerWheel.tsx:463), whichspec:AST-094FR9 rules out.
[Automated review]
| styles.stripRowAt(`${position * ROW_HEIGHT}px`), | ||
| option.isDisabled && styles.rowDisabled, | ||
| )}> | ||
| <span |
There was a problem hiding this comment.
On short lists each touch wheel's fixed nodes (the options wrapper, drum, band copy, strip, and a row plus this span for up to seven strip positions) outnumber what they save: the head's BottomSheetNarrowRange story counts 1,031 elements under a coarse pointer against 1,012 under a fine one with the month and year wheels open, past the 5 that spec:AST-017 FR60 allows an open layer. Trim these nodes for short lists, or include these counts in the INV7 exception the description asks the design owner to record.
There was a problem hiding this comment.
Trimmed in e47456a: the narrow sheet's month and year wheels went from 1,030 to 1,019 elements under a finger (1,011 under a mouse), pixel-identical. The remaining 8 over spec:AST-017 FR60's 5 are in the INV7 exception the description asks the design owner to record, with these counts.
|
The touch wheel's look and its rest rule decide what every bottom-sheet date and time wheel draws and commits under a finger, and neither can merge without an owner's record. One question each, with our reading and evidence. 1. The look's record. Will you record the look in the touch wheel's record, with its band filled by
2. The rest rule. Will you approve DateInput FR13 / DEC-1 and DateTimeInput FR8 as they read: a wheel that stops on a disabled row continues to the nearest enabled row (a tie toward the committed row) and commits it there, and a rest on the committed row commits nothing, even outside the bounds?
|
There was a problem hiding this comment.
This review is on hold for an owner decision: no current spec governs the touch wheel's UIPickerView look, since spec:AST-094 covers touch behavior only, and the head adds the draft rest rule in component:DateInput FR13/DEC-1 and component:DateTimeInput FR8. An engineering or design owner needs to provide or identify the record that governs the look, its --color-neutral band fill and the INV7/FR60 exception its band copy and extra touch elements need, and to approve or reject the rest rule; any engineering owner, the author included, records that decision by commenting /approve-spec <full head SHA> once the head carries that record. Whatever the decision, these points need changes:
- Land #8527 and its predecessors first and merge
main, where seven files now conflict with the landed animator, so this diff carries only the look (3,121 authored lines instead of 34,966), then split it or show why it has to stay together. - A drag re-renders the wheel through
flushSyncwhenever it leaves the mounted rows (PickerWheel.tsx:460, called from the pan's moves at:722), whichspec:AST-094FR9 rules out. - Under reduced motion the cross-fade lands its rows on a main-thread timer (
wheelMotion.ts:421-427), so a busy page fades back in on the old rows, against FR5.
[Automated review]
| // A motion's animations are baked per mounted row as it starts, and | ||
| // a drag frame writes the mounted rows: both need the rows now. | ||
| // eslint-disable-next-line @eslint-react/dom-no-flush-sync, @eslint-react/set-state-in-effect -- see above; never called from an effect with `now` | ||
| flushSync(() => setRowWindow(next)); |
There was a problem hiding this comment.
This flushSync runs from the pan's began and changed handlers (lines 709 and 722) whenever the offset leaves the mounted window, so the column renders synchronously inside a touch move. spec:AST-094 FR9 requires "no component render per move". Moving the window inside WheelMotion by recycling the mounted drum and strip nodes would keep the drag path to style writes.
There was a problem hiding this comment.
Recorded under the description's Known issue (spec:AST-094 FR9): the mounted window is React state, so a drag that leaves it renders the column. The fix recycles the drum and strip nodes imperatively in WheelMotion, once the design owner rules on this look; it is the same rework as the landing below.
There was a problem hiding this comment.
Fixed in 4e810c2, with the thread above: the flushSync is gone; a drag recycles the mounted drum and strip rows imperatively (wheelRows.ts), so its path is style writes only (0 renders through a ten-row drag, 3 before).
| motion.timers.push( | ||
| window.setTimeout(() => { | ||
| if (this.motion === motion) { | ||
| onMidpoint?.(); | ||
| this.render(to, true); | ||
| } | ||
| }, durationMs / 2), |
There was a problem hiding this comment.
The rows land at the fade's midpoint on a main-thread timer, and onMidpoint mounts them, through flushSync when they lie outside the mounted window. If the main thread is busy then, the opacity fade comes back in on the old rows and they jump once the timer runs, which spec:AST-094 FR5 rules out ("MUST keep advancing at display rate through a main-thread block"). Mounting the destination rows before the fade and landing them inside the same Web Animations would keep the landing on the compositor.
There was a problem hiding this comment.
Recorded under the description's Known issue (FR5). Today's look already lands on the compositor (#8526 bakes the destination into the rows' own animations, and #8162 proves it through a 700 ms block); the look adopts that with the node recycling FR9 needs, once the design owner rules. Its busy-landing browser case is marked to fix there.
There was a problem hiding this comment.
Fixed in 4e810c2: the wheel mounts the rows around both ends of the fade before it starts (not the rows between), and the player bakes the landing as #8526 does: the destination inline first, each row and the strip holding the origin in an animation that steps onto it at the midpoint, on the compositor, timed from when the animations start. The Chromium busy-main-thread proof is no longer fixme: before, minute 01 reached the band only when a 700 ms block ended; after, every frame from the midpoint shows it there (6 of 6). On the iOS simulator, with the main thread blocked 600 ms after the tap, the fade and the landing now play through the block.
There was a problem hiding this comment.
This review is on hold for an owner decision: no current spec governs the touch wheel's UIPickerView look, since spec:AST-094 covers touch behavior only, and the head adds the draft rest rule in component:DateInput FR13/DEC-1 and component:DateTimeInput FR8. An engineering or design owner needs to provide or identify the record that governs the look, its --color-neutral band fill and the INV7/FR60 exception its band copy and extra touch elements need, and to approve or reject the rest rule; any engineering owner, the author included, records that decision by commenting /approve-spec <full head SHA> on the pull request once the head carries that record. Whatever the decision, these points need changes:
- Land #8527 and its predecessors first and merge
main, where threeinternal/interaction-harnessfiles still conflict, so this diff carries only the look (3,281 authored lines instead of 34,606), then split it or show why it has to stay together. - A drag re-renders the wheel through
flushSyncwhenever it leaves the mounted rows (PickerWheel.tsx:460, called from the pan's moves at:722), whichspec:AST-094FR9 rules out. - Under reduced motion the cross-fade lands its rows on a main-thread timer (
wheelMotion.ts:421-427), so a busy page fades back in on the old rows, against FR5.
[Automated review]
…nto uikit/c21-wheel-proofs
…nto uikit/c21-wheel-listbox
…nto uikit/c21-wheel-short-loop
…nto uikit/c21-wheel-rest-and-spin
…nto uikit/c21-wheel-look
…o their own changesets In the same release meta#8179's time columns loop, so "no shipped column loops yet" would contradict it; the columns that loop say so themselves.
…heirs) into uikit/c21-wheel-rest-and-spin
…heirs) into uikit/c21-wheel-look
…tep a frame from the change that ends it Against the control, a frame with no new component position was a miss. On an easing tail the component moves under one cast step a frame, which the screencast cannot show on every frame: Lightbox's dismiss-cancel proof in WebKit missed one of the control's 12 to 14 frames in 7 of 10 runs, each time at its spring's last plateau (210, 210, then 208 on WebKit's 2 px grid). Such a run of unchanged frames now counts as moved when the change that ends it is a single cast step. A freeze ends in a catch-up of more than one step and stays a miss, as does a run that no change ends, and the component must still show a new position on at least minJudgedFrames of the control's frames, so a frame-counted animation that stands still through the block and resumes one step a frame fails too. The cast step is read from the tracked value's changes in the judged part rather than from its positions: the photo's position once the block ended (207) sat off WebKit's 2 px grid and made the step read as 1 px. Red first: the tail, pooled tail, off-grid commit and frame-counted freeze cases fail on the previous busy.ts; the single-miss, slow freeze and stop-for-good cases still fail. Lightbox's five busy proofs with this judgment: 30 of 30 in Chromium, 39 of 40 in WebKit (the other presented 3 frames in its judged part, under the 4 a window needs). The harness's own proofs still pass a compositor animation with no miss and fail the rAF one (0 of 39 to 47 control frames) in both engines.
…awn PM row, and the 1 s busy proof follows rows in turn - The clamped-turn proof taps the PM row where the cylinder draws it. - UIPickerView's cylinder foreshortens a row as it turns away from the band and leaves the band's row to the band's copy, so no one row stays in sight, moving a pixel a frame, for the whole 1 s block. Rows take turns: each is followed from three and a half rows below the band until it reaches the band's edge, and the harness judges each stretch, which together cover the whole block.
…ng curve only when it is at most a frame longer than the run before it astracat found that the sub-step credit let pooledBusyProof pass a rAF loop that steps a fixed 1 or 2 px a frame: in each 70 ms block the cast still shows the loop's last steps, then it stands still and goes on one step a frame without catching up, so its run ended in a single step. With the previous busy.ts the self-test's frame-counted loop passed the pooled proof in 5 of 5 Chromium runs. A slowing curve lengthens its runs a frame at a time, so a run now counts as moved only when it is at most one frame longer than the component's run before it; a stall is longer than the runs before it. A judged part with no change reads the finest cast step, 0.5 px, so a larger jump never passes for one step. The self-test adds the frame-counted loop, at 1 and 2 px a frame, to the pooled proof's mutants: it fails every pool (Chromium 10 of 10, moved on 2 to 8 of 7 to 12 control frames; WebKit 10 of 10, 0 or 1 of 11 or 12). The timed rAF mutant can read as moved on one control frame, presented as the block starts, so its assertion takes 0 or 1 and also requires its stall to exceed the control's (Chromium showed 1 of 40 once). Red first: the frame-counted stall, the pooled frame-counted loop and the finest-step cases fail on the previous busy.ts. Lightbox's five busy proofs with this judgment: 30 of 30 in Chromium; 33 of 40 in WebKit with no miss, the other 7 presenting too few control frames to judge.
… turn through the 1 s block) into uikit/c21-wheel-fr43
There was a problem hiding this comment.
This pull request waits on an owner decision: approval needs an engineering or design owner to provide or identify the governing spec for the touch wheels' UIPickerView look (component:DateInput DD1), for its exception to architecture:component-style-authoring INV7 and spec:AST-017 FR60 (PR3), and for the rest rule in component:DateInput FR13/DEC-1 and component:DateTimeInput FR8, none of which has current spec authority, and the earlier design approval predates DD1 and PR3. An engineering owner records that decision by commenting /approve-spec <full head SHA> on this pull request; the author may do so as an engineering owner. Whatever the decision, these changes are needed:
- Land #8527 first and rebase, since this diff carries 37,949 authored lines, 36,258 of them that stack.
- Record the TimeInput sheet's look and INV7 exception in
component:TimeInput, which owns that sheet, or narrow DD1 and PR3 to DateInput's own wheels. - Report INV6 sizes against the base, and restate the band-magnification note in
motion/uikit/picker.tsto match the drawing.
[Automated review]
| - **PR2 — Scroll work.** Scroll-driven measurement and selection updates remain | ||
| animation-frame throttled or settle-driven; listeners, frames, timers, and observers | ||
| are cleaned up on deactivation or unmount. | ||
| - **PR3 — The touch wheel draws each label three times.** Under a finger, a sheet's |
There was a problem hiding this comment.
PR3 names TimeInput's counts, but component:TimeInput is current and owns "the bottom-sheet time wheels", and architecture:component-style-authoring INV7 records an exception "in the component's current record or, when the component has none, in this record". This record is draft and its own Owns line (line 90) gives the time wheels to TimeInput and DateTimeInput. Recording the TimeInput sheet's exception in component:TimeInput, or narrowing PR3 and DD1 to DateInput's month and year wheels, would put each exception where INV7 looks for it.
| */ | ||
| bandInset: 9, | ||
| /** | ||
| * The band's copy of the rows is magnified about the picker's centre: |
There was a problem hiding this comment.
This note says the band copy is magnified about the picker's centre, with band digits about 11 pt outward, but PickerWheel.tsx magnifies each label about its own centre and wheelColumns.ts records UIKit doing exactly that. Restating the note from the UIDatePicker measurement keeps the value's source in line with the drawing (spec:AST-094 FR2).
…its wheels' look and exception; the band note matches the drawing - DateInput's DD1 and PR3 now cover its own month and year wheels; the TimeInput and DateTimeInput sheets record their wheels' UIPickerView look (DD1) and the INV7 exception for the labels drawn three times (PR2) in their own records, which own those sheets. TimeInput's sheet has 250 elements under a finger against 286 under a mouse; DateTimeInput's open sheet 377 against 470. - The band-magnification note in picker.ts says what UIKit draws and what the wheel draws: each band label magnified about its own centre, as wheelColumns.ts records. The value is unchanged.
… long a frame takes The proof's guard compared the longest frame gap of two openings under CPU throttling, and the load on the machine running it moved that gap more than the wheel did: at one head the 200-year opening's worst gap ran from 266 to 516 ms, against 183 to 233 ms for two years, so the guard failed now and then on a busy machine. It now counts the year wheel's elements the opening writes or adds, from the tap until the wheel rests: 1 for two years and 19 for 200, the same on every run. A cost per year shows as 200 or more. Counting needs no CPU throttling, so the proof runs in WebKit too. It waits for the wheel to rest instead of a fixed 1.5 s, and the sheet's wait no longer swallows a failure.
There was a problem hiding this comment.
This pull request waits on an owner decision: the touch wheels' UIPickerView look (DD1 in the DateInput, TimeInput and DateTimeInput records), the exceptions for labels drawn three times (DateInput PR3, TimeInput PR2, DateTimeInput PR2) and the rest rule (DateInput FR13/DEC-1, DateTimeInput FR8) have no current spec authority, so approval needs an engineering owner to provide or identify the governing spec for them by approving or rejecting them as written, including where DateInput's and DateTimeInput's exceptions are recorded while those records are draft. 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; a design owner's exact-head approval covers the Design decisions rows. Whatever the decision, these changes are needed:
- Land #8527 first and rebase: this diff carries 37,979 authored lines, 36,249 of them that stack.
- Report the INV6 component sizes against the base rather than against #8527.
- Add FR13's and FR8's "turn onto the new row rather than jump" sentence to DEC-1 for approval, or mark it pending, instead of calling it settled by DEC-1.
[Automated review]
| | FR10 | Standalone mode MUST compose Field; admitted InputGroup mode MUST remove competing Field chrome while preserving name, description, value, keyboard, focus, and editing semantics. | `family:input-fields/FR3`; current source and InputGroup tests | Settled shared rule and verified adoption | | ||
| | FR11 | Clear MUST emit `undefined` through the ordinary change pipeline. The pointer and bottom-sheet surfaces restore field focus using their shipped timing; the native surface MUST NOT reclaim focus because doing so reopens the OS picker. Implementation gap: when the field becomes disabled or busy while its clear control holds focus, the control unmounts and focus falls to the document body; `spec:AST-085/FR4` requires focus to stay or move to a destination this record names. | Current source and focused clear tests; `spec:AST-085/FR4` | Verified shipped behavior | | ||
| | FR12 | No surface renders native `disabled`. A disabled field MUST stay focusable with `aria-disabled`, block typing, picking, clearing, and opening, describe its disabled reason when one is given, and take disabled paint. While busy (`isLoading` or a pending Action) the pointer and bottom-sheet surfaces expose `aria-disabled` and `aria-busy`, stay focusable, and block new commits; the native surface does the same for `isLoading`, and during a pending Action stays editable so the OS picker remains attached but rejects additional commits until the Action settles. A busy field that is not disabled keeps its ordinary paint and Spinner, shows no hover ring while commits are blocked, and keeps its keyboard focus ring. | `spec:AST-085/FR1–FR6`; `family:input-fields/FR4–FR6`; `family:buttons/FR4`; current source and focused tests | Settled shared rule and verified adoption | | ||
| | FR13 | A bottom-sheet picker wheel that comes to rest on a disabled row (outside `min`/`max`) MUST continue to the nearest enabled row, a tie going toward the committed row, and select it there. A wheel resting on its committed row MUST NOT select or commit, even when that row is outside the bounds, so opening a bounded sheet never changes an untouched value: a committed value outside the bounds stays, and an empty field stays empty. A shown wheel whose value changes from outside, as when a bound clamps the time after another wheel turned, MUST turn onto the new row rather than jump to it. | DEC-1; UIDatePicker on the iOS 26.2 simulator; wheel unit and real-browser tests | Settled by DEC-1 | |
There was a problem hiding this comment.
This row is marked "Settled by DEC-1", but its last sentence ("a shown wheel … MUST turn onto the new row rather than jump to it") is not in DEC-1, which decides only the continue-to-nearest rest and the untouched value. component:DateTimeInput FR8 repeats it as settled too. Adding the rule to DEC-1 for the owner to approve, or marking that sentence pending owner approval, keeps the row from reading as already decided.
…il cancelled, and its compositor run is blocked only once on the compositor C23 saw the control self-test fail under load at eight workers: "660 ms judged at 16.6 ms/frame: 28 frames presented, 0/28 moved". Its animations ran once, for 1,600 ms from before the screencast started, so on a loaded runner, where starting the cast takes long, the compositor's animation had ended before the block and nothing moved in the judged part. Both animations now go back and forth until cancelled, as the pooled self-test's do, and the compositor's block uses `during`, so it starts only once that animation runs on the compositor. Red first: with the setup stretched to 1.8 s, as a loaded runner takes, the previous test fails with exactly that read (0/39 moved) and this one passes. Normal runs at eight workers: 10 of 10 in Chromium and 10 of 10 in WebKit.
… control) into uikit/c21-wheel-proofs
…pending owner approval [skip ci] FR13 and DEC-1 settle where a wheel rests. The turn of a shown wheel onto a value changed from outside, as when a bound clamps the time after another wheel turned, sat inside FR13 and DateTimeInput FR8, so both read it as settled by DEC-1, which doesn't decide it. It is now DateInput FR14, the shared wheel's own requirement, a verified observation pending owner approval; DateTimeInput FR8 keeps only the rest, and the two tests that prove the turn cite FR14.
…nst a compositor-only control [skip ci] The 1 s busy proof marked one row and asked that every frame the compositor presented show it moved. Two things made it fail on a busy machine. Late in the block the coast moves about a pixel a frame, under the screencast's step, so a frame delivered early shows no change; and over a whole second the coast travels further than the column shows, so the marked row was out of sight at one end, turned and faded at the other. It now follows markers that ride the strip itself, every three rows in three colours, placed before the flick so the block meets them already on screen. They move with the coast and never turn or fade, and each is judged while within reach of the band; together they cover the block. The judgment is busyWindowProof's against a compositor-only control recorded in the same frames (meta#8906): the coast moves on every frame the control moves, a run under one step that a single step ends counts as moved, and its longest stall is no longer than the control's.
…wheel-uikit-look # Conflicts: # packages/core/src/DateInput/DateInput.spec.md
… into uikit/c21-wheel-uikit-look # Conflicts: # packages/core/src/DateInput/__tests__/Wheel.interaction.browser.spec.ts # packages/core/src/DateInput/__tests__/WheelActivation.interaction.browser.spec.ts
…R14 [skip ci] meta#8131 made the turn its own requirement, DateInput FR14, pending owner approval; the wheel's park note and its test said FR13.
…) into uikit/c21-wheel-trackpad-glide
There was a problem hiding this comment.
This pull request waits on an owner decision: the touch wheels' UIPickerView look (DD1 in the DateInput, TimeInput and DateTimeInput records), the exceptions for labels drawn three times (DateInput PR3, TimeInput PR2, DateTimeInput PR2), the rest rule (DateInput FR13/DEC-1, DateTimeInput FR8) and the new DateInput FR14 have no current spec authority, so approval needs an engineering owner to provide or identify the governing spec by approving or rejecting them as written, including where the two draft records' exceptions belong. 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; a design owner's exact-head approval covers the Design decisions rows. Whatever the decision, the diff needs to shrink: it carries 39,085 authored lines, 37,357 of them the still-open stack under #8527, so land that stack first and rebase until this pull request is the look alone.
[Automated review]
| - **PR2 — Scroll work.** Scroll-driven measurement and selection updates remain | ||
| animation-frame throttled or settle-driven; listeners, frames, timers, and observers | ||
| are cleaned up on deactivation or unmount. | ||
| - **PR3 — The touch wheels draw each label three times.** Under a finger, the sheet's |
There was a problem hiding this comment.
This exception sits in a draft record, so it passes no spec-owner gate on its own: architecture:component-style-authoring INV7 records an exception "in the component's current record or, when the component has none, in this record". Until an owner approves it at an exact head and says where it lives (this record made current, or the exception moved into INV7's record), "an owner exception" overstates it. The same holds for component:DateTimeInput PR2.
Depends on #8527. Review only this PR's change: vjeux/astryx@1d7ee3e...4f789d9
User need
On a phone, the date and time sheets' wheels move like the iOS picker (#8159) but still look like the desktop column, flat rows on an accent plate. People know the iOS picker by its look as much as its motion. This draws the touch wheels as UIPickerView does; a mouse keeps today's column.
Problem and solution fit
What led to it: Astryx's UIKit-parity work (
spec:AST-094) makes its phone presentations behave like iOS, and the stack below matched the wheel's motion to UIKit's. Measuring UIKit's picker on the iOS 26.2 simulator gave the rest, drawn here:Current specification
spec:AST-094FR1, FR5, FR42;design:reduced-motionDR2. The look and its element exception sit in the record that owns each sheet:component:DateInputDD1 and PR3 for its month and year wheels, andcomponent:TimeInputDD1 and PR2 andcomponent:DateTimeInputDD1 and PR2 for their sheets' wheels. All three records' owner is cixzhang;component:TimeInputis current, so its rows are a proposed change to a current record, and the others are draft. Whether they stand is the owner's decision.Public delta and caller burden
No API change. Size (INV6, gzip, the size report's own measure):
Against main the imports carry the whole stack below (the gesture system, the wheel's physics, player and rest), whose pull requests report their own parts. This pull request's own step stays under INV6's 2 KB JavaScript and 1 KB CSS flags for touch-only code.
Design and alternatives
Evidence
iOS 26.2 simulator, this head; UIKit is Safari's own picker, Before is today's look:
The look the design owner approved, and this head (28 px rows, secondary colour):
Scope
Writing rubric results
Over
DateInput.spec.md,TimeInput.spec.mdandDateTimeInput.spec.md: R1 narration, none; R2 research, none (the element counts are the sheets' own); R3 evidence, no pull requests or commits; R4 rejected alternatives, one (DateInput DEC-1), one line; R5 change references, none; R6 open questions, none.pnpm check:knowledgepasses.Testing
On a phone or the iOS simulator, open Storybook's TimeInput › Bottom Sheet With Min Max:
Automated tests hold the 28 px rows, the 4.5:1 contrast in light and dark, and the catch, in jsdom and in Chromium; each fails without its change. At this head the core suite (15,356 tests) passes, and the date, time and wheel browser specs pass in Chromium (89 accessibility, 11 interaction, including the one-second busy-page proof). Not this change: the root-entry bundle check fails on main's test, which #8671 fixes.
Since b4b2032: the stack below moved to its new heads; the look's two browser proofs follow it (the clamp proof taps the PM row where the cylinder draws it, and the one-second busy proof follows rows in turn, since the cylinder hides a row as it crosses the band); each sheet's record now holds its wheels' look and exception; and the band-magnification note in
picker.tssays what UIKit draws, each band label magnified about its own centre.