Repository navigation
spec(AlertDialog): touch presentation, phone width, and action-group actions (FR6–FR9) - #8594
Conversation
…ut hold, action tracking, themed width (FR6–FR9, OQ1–OQ3)
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
AI review status for this pull request.
|
…th from a general compact-dialog role
PR Analysis ReportView Storybook for this PR · View Sandbox for this PR
Generated by PR Enrichment workflow | View current CI run |
|
Posted by Cindy's agent on her behalf. Cindy's decision on taps during an entrance: every touch presentation absorbs taps and drags that land during its entrance. This covers alerts, sheets and dialogs, extending |
|
Posted by Cindy's agent on her behalf. Cindy's decision on alert width: on phones (compact width with a touch pointer), alerts are 320 px wide in every theme, matching iOS, with no new theme role. Desktop is unchanged. The AlertDialog record states this, and the code conforms to it. |
… on phones in every theme (DEC-2); OQ2 stays open
|
Posted by Cindy's agent on her behalf. Cindy's decision on sliding between actions: a group of actions behaves like a menu under a press. Press an action, slide across its sibling actions with the highlight following, and the action you lift on runs. Sliding off the group cancels. One shared module, the existing action-group tracker, governs this for menus, SegmentedControl, AlertDialog's actions, Dialog's action/footer area (not arbitrary dialog content), ButtonGroup and ToggleButtonGroup. In a toggle group, only the item you lift on toggles; sliding across never toggles the items in between. Keyboard and screen-reader behavior is unchanged. The record amendment to |
vjeux
left a comment
There was a problem hiding this comment.
Four places where this record differs from what has landed or been decided since its last push (23:34Z):
- FR9 gives the width to a general compact-dialog theme role (400 px by default, 320 px from an iOS-style theme). The width decision on #8084 (23:32Z) is: on phones (compact width with a touch pointer), alerts are 320 px wide in every theme, with no new theme role; desktop is unchanged.
- FR6 names the roles
springs.alertPresentandsprings.alertDismiss. Since f3e51b5 (#8084) they arealert.presentandalert.dismiss, in the alert's own motion table. - FR8 tracks a finger across the actions under a touch presentation only.
spec:AST-094DEC-17 andfamily:action-groupsFR5 (#8622) apply the slide to every pointer. - #8084 states the phone width as
component:AlertDialogFR6 (b52c90c), which collides with this record's FR6.
There was a problem hiding this comment.
Approval waits on an engineering owner's decision on the new draft requirements in component:AlertDialog: FR6 (touch motion), FR7 (entrance input hold), FR8 (action tracking), FR9 (compact-dialog width role) and PR2. That decision includes whether FR7 and FR8 should wait for the planned spec:AST-094 FR35 and FR26–FR28 amendments. An engineering owner records it by commenting /approve-spec 041b34add94af2cc9750c4fa08081ec226e92cdb, and the author may do so as an engineering owner. Whatever the decision, these fixes are needed before approval:
- Restore PR1 under Performance and resources, which is now a literal
\1. - Rewrite FR9, its verification row and OQ3 to the width decision posted on this pull request (320 px on phones in every theme, no new theme role), and say whether a caller's
widthprop still wins. - Give FR8 the
presentationvalue thatarchitecture:public-component-apiINV16 requires for a touch input mode, and update the Compatibility lines that still say nothing changes.
[Automated review]
| - **PR1 — Dialog-owned resources.** AlertDialog's only listener is the | ||
| small-screen media query behind the button order; Dialog owns the modal | ||
| lifecycle. | ||
| \1 |
There was a problem hiding this comment.
This line is a literal \1 where PR1 used to be ("AlertDialog's only listener is the small-screen media query behind the button order; Dialog owns the modal lifecycle"). Restore PR1. Restate it if FR7 or FR8 would add touch input handling, since its "only listener" sentence would then be false.
| | FR6 | Under a touch presentation (`spec:AST-094` FR13), a modal AlertDialog presents by scaling from 1.2 to 1 with its opacity and its backdrop's dimming rising from 0 to 1 on the motion role `springs.alertPresent`, started at the browser's commit, with the larger start kept inside the viewport; it dismisses by a fade alone on `springs.alertDismiss` and closes at the fade's end; a close during the presentation, or a reopen during the dismissal, springs from where it is. The roles are internal with UIKit's measured values (`spec:AST-094` FR4, DEC-11). Under Reduce Motion both are the shared cross-fade (`design:reduced-motion` DR1–DR3). A fine primary pointer keeps today's motion (`spec:AST-094` FR19). | proposed from measured iOS 26.2 behavior | owner review | | ||
| | FR7 | Under a touch presentation, pointer input to the alert is held from the presentation's start until it can be read, through the layer runtime's shared input hold; keyboard and assistive-technology input are never held, and the entrance never makes the content inert. While the alert leaves, its content is inert for the dismissal fade. The hold's timing stays internal (`spec:AST-002` FR3). | proposed; pending owner decision (OQ1) | owner decision | | ||
| | FR8 | Under a touch presentation, a finger that slides from one action to another runs the action it lifts on, as a menu's press-tracking slide does (`spec:AST-094` FR26–FR28). | proposed; pending owner decision (OQ2) | owner decision | | ||
| | FR9 | The alert's width comes from a general compact-dialog width theme role, shared with Dialog's compact size and confirmation sheets, defaulting to today's 400 px; an iOS-style theme sets 320 px. AlertDialog does not set a touch width of its own. | proposed; pending owner decision (OQ3) | owner decision | |
There was a problem hiding this comment.
FR9 proposes a shared compact-dialog theme role (400 px by default, 320 px in an iOS-style theme). The width decision posted on this pull request is 320 px on phones in every theme, with no new theme role. FR9, its verification row and OQ3 should follow that decision and say whether a caller's width prop still wins.
| | FR5 | `useImperativeAlertDialog` returns `show`, `hide`, and the element to render, and owns `isOpen`/`onOpenChange` for its caller. | shipped source and focused tests | verify | | ||
| | FR6 | Under a touch presentation (`spec:AST-094` FR13), a modal AlertDialog presents by scaling from 1.2 to 1 with its opacity and its backdrop's dimming rising from 0 to 1 on the motion role `springs.alertPresent`, started at the browser's commit, with the larger start kept inside the viewport; it dismisses by a fade alone on `springs.alertDismiss` and closes at the fade's end; a close during the presentation, or a reopen during the dismissal, springs from where it is. The roles are internal with UIKit's measured values (`spec:AST-094` FR4, DEC-11). Under Reduce Motion both are the shared cross-fade (`design:reduced-motion` DR1–DR3). A fine primary pointer keeps today's motion (`spec:AST-094` FR19). | proposed from measured iOS 26.2 behavior | owner review | | ||
| | FR7 | Under a touch presentation, pointer input to the alert is held from the presentation's start until it can be read, through the layer runtime's shared input hold; keyboard and assistive-technology input are never held, and the entrance never makes the content inert. While the alert leaves, its content is inert for the dismissal fade. The hold's timing stays internal (`spec:AST-002` FR3). | proposed; pending owner decision (OQ1) | owner decision | | ||
| | FR8 | Under a touch presentation, a finger that slides from one action to another runs the action it lifts on, as a menu's press-tracking slide does (`spec:AST-094` FR26–FR28). | proposed; pending owner decision (OQ2) | owner decision | |
There was a problem hiding this comment.
FR8 changes how the open alert follows a finger, so architecture:public-component-api INV16 asks for a presentation value that keeps the fine-pointer input mode. The record names none, and its Compatibility section still says the released default is preserved.
|
/approve-spec edabb48 |
There was a problem hiding this comment.
Requesting changes: an engineering owner approved this head's direction, but the record still has a few issues to fix before it lands. FR8 cites family:action-groups and spec:AST-094 DEC-17, which only exist in #8622, and current spec:AST-094 FR11 still keeps a button's activation on the browser's click, so please land #8622 first and rebase, or move FR8 to a follow-up. Please also:
- Rewrite the FR9 verification row, which still tests the theme role that FR9 and DEC-2 reject.
- Fill in the FR8 verification row's states, failure expectation and audit section.
- Update the Compatibility lines and Contract at a glance, and say in FR9 whether an explicit
widthstill wins on a phone. - Point FR6's citations at current
spec:AST-094text (FR13 and the Non-goals instead of FR19, FR4 and DEC-15 instead of DEC-11), and drop FR7's mechanism clause.
[Automated review]
| | FR5 | `useImperativeAlertDialog` returns `show`, `hide`, and the element to render, and owns `isOpen`/`onOpenChange` for its caller. | shipped source and focused tests | verify | | ||
| | FR6 | Under a touch presentation (`spec:AST-094` FR13), a modal AlertDialog presents by scaling from 1.2 to 1 with its opacity and its backdrop's dimming rising from 0 to 1 on the motion role `springs.alertPresent`, started at the browser's commit, with the larger start kept inside the viewport; it dismisses by a fade alone on `springs.alertDismiss` and closes at the fade's end; a close during the presentation, or a reopen during the dismissal, springs from where it is. The roles are internal with UIKit's measured values (`spec:AST-094` FR4, DEC-11). Under Reduce Motion both are the shared cross-fade (`design:reduced-motion` DR1–DR3). A fine primary pointer keeps today's motion (`spec:AST-094` FR19). | proposed from measured iOS 26.2 behavior | owner review | | ||
| | FR7 | Under a touch presentation, pointer input to the alert is held while it enters, through the layer runtime's shared input hold (`spec:AST-094` FR35); keyboard and assistive-technology input are never held, and the entrance never makes the content inert. While the alert leaves, its content is inert for the dismissal fade. The hold's timing stays internal (`spec:AST-002` FR3). | `spec:AST-094` FR35; owner decision (DEC-1) | decided | | ||
| | FR8 | AlertDialog's actions are an action group (`family:action-groups`): a press that slides across them runs the action it lifts on, and a lift outside them runs nothing, under every pointer; keyboard and assistive-technology behavior is unchanged. | `family:action-groups`; `spec:AST-094` DEC-17 | decided | |
There was a problem hiding this comment.
family:action-groups and spec:AST-094 DEC-17 are not on main yet; both arrive with #8622. Meanwhile current spec:AST-094 FR11 keeps a button's activation on the browser's click, and FR26–FR28 cover only useMenuPress surfaces. Land #8622 first and rebase so these citations resolve, or move FR8 and its verification row to a follow-up. spec:AST-017 FR59 also asks the mouse change to carry its own owner decision, and this record's decision log has none for FR8.
| | FR6, PR2 | Browser tests under a coarse pointer in Chromium and WebKit, a spring-curve oracle, a busy-main-thread case, and real-device clips on iOS Safari and Android Chrome | present, dismiss, close during present, reopen during dismiss, Reduce Motion, a fine pointer, a narrow viewport | a curve off its role, a start outside the viewport, a jump on interruption, a scale under Reduce Motion, changed motion under a fine pointer, or an added element fails | `audit:AlertDialog/behavior` | | ||
| | FR7 | Browser tests under a coarse pointer, with keyboard and assistive-technology input | a tap during the presentation, Enter and Escape during it, a screen reader's activation, a tap during the dismissal | a held key or assistive-technology action, content made inert during the entrance, or a tap that reaches a leaving alert fails | `audit:AlertDialog/behavior` | | ||
| | FR8 | Pointer-stream tests with a mouse, a pen, and a finger, and keyboard tests | | | | | ||
| | FR9 | Browser tests at a phone width and at a desktop width, in the default and an alternate theme | the default theme, an iOS-style theme, and Dialog's compact size reading the same role | a width other than the theme's fails | `audit:AlertDialog/behavior` | |
There was a problem hiding this comment.
This row still tests the theme role that FR9 and DEC-2 reject ("an iOS-style theme, and Dialog's compact size reading the same role", "a width other than the theme's"). Suggest testing a phone width under a coarse pointer and a desktop width under a fine pointer, in the default and one alternate theme, and failing on any phone width other than 320 px in any theme or any change to the desktop width.
| | FR1–FR5 | `AlertDialog.test.tsx` ("calls onOpenChange(false) on Escape", "does not call onOpenChange when action is clicked", "does not call onAction on Escape", "does not disable the cancel button while the action is loading", "exposes a named group instead, with no aria-modal") and `useImperativeAlertDialog.test.tsx` ("opens on show()", "closes on hide()") | open, loading, inline, imperative | Escape not cancelling, the action closing by itself, or the inline path claiming the role fails. | `audit:AlertDialog/behavior` | | ||
| | FR6, PR2 | Browser tests under a coarse pointer in Chromium and WebKit, a spring-curve oracle, a busy-main-thread case, and real-device clips on iOS Safari and Android Chrome | present, dismiss, close during present, reopen during dismiss, Reduce Motion, a fine pointer, a narrow viewport | a curve off its role, a start outside the viewport, a jump on interruption, a scale under Reduce Motion, changed motion under a fine pointer, or an added element fails | `audit:AlertDialog/behavior` | | ||
| | FR7 | Browser tests under a coarse pointer, with keyboard and assistive-technology input | a tap during the presentation, Enter and Escape during it, a screen reader's activation, a tap during the dismissal | a held key or assistive-technology action, content made inert during the entrance, or a tap that reaches a leaving alert fails | `audit:AlertDialog/behavior` | | ||
| | FR8 | Pointer-stream tests with a mouse, a pen, and a finger, and keyboard tests | | | | |
There was a problem hiding this comment.
This row has no representative states, failure expectation or audit section, so nothing can fail it. Suggested states: a press on Cancel slid onto the action and lifted, and a press lifted outside the actions, each with a mouse, a pen and a finger, plus Enter and Space. Suggested failure: the press-start action running after a slide, any action running on a lift outside, or a changed keyboard or assistive-technology path. Audit section: audit:AlertDialog/behavior.
| | FR3 | The anatomy is title, description, then the buttons: Cancel then action on wider screens, the action stacked above Cancel on small screens, Cancel keeping initial focus either way; the action may show a loading state while `isActionLoading`. | shipped source and focused tests | verify | | ||
| | FR4 | `isInline` renders the same anatomy without modality and without the alert-dialog role. | shipped source and public docs | verify | | ||
| | FR5 | `useImperativeAlertDialog` returns `show`, `hide`, and the element to render, and owns `isOpen`/`onOpenChange` for its caller. | shipped source and focused tests | verify | | ||
| | FR6 | Under a touch presentation (`spec:AST-094` FR13), a modal AlertDialog presents by scaling from 1.2 to 1 with its opacity and its backdrop's dimming rising from 0 to 1 on the motion role `springs.alertPresent`, started at the browser's commit, with the larger start kept inside the viewport; it dismisses by a fade alone on `springs.alertDismiss` and closes at the fade's end; a close during the presentation, or a reopen during the dismissal, springs from where it is. The roles are internal with UIKit's measured values (`spec:AST-094` FR4, DEC-11). Under Reduce Motion both are the shared cross-fade (`design:reduced-motion` DR1–DR3). A fine primary pointer keeps today's motion (`spec:AST-094` FR19). | proposed from measured iOS 26.2 behavior | owner review | |
There was a problem hiding this comment.
On main, spec:AST-094 FR19 now says recognizers attach for every pointer, so it no longer backs "A fine primary pointer keeps today's motion"; FR13 and the Non-goals do. DEC-15 also supersedes DEC-11's "all internal", so the theme's tempo and character knobs reach these roles (FR4). Suggest citing FR13 and FR4 with DEC-15, updating system_specs, and aligning FR6's Draft review state with FR7–FR9.
| | FR4 | `isInline` renders the same anatomy without modality and without the alert-dialog role. | shipped source and public docs | verify | | ||
| | FR5 | `useImperativeAlertDialog` returns `show`, `hide`, and the element to render, and owns `isOpen`/`onOpenChange` for its caller. | shipped source and focused tests | verify | | ||
| | FR6 | Under a touch presentation (`spec:AST-094` FR13), a modal AlertDialog presents by scaling from 1.2 to 1 with its opacity and its backdrop's dimming rising from 0 to 1 on the motion role `springs.alertPresent`, started at the browser's commit, with the larger start kept inside the viewport; it dismisses by a fade alone on `springs.alertDismiss` and closes at the fade's end; a close during the presentation, or a reopen during the dismissal, springs from where it is. The roles are internal with UIKit's measured values (`spec:AST-094` FR4, DEC-11). Under Reduce Motion both are the shared cross-fade (`design:reduced-motion` DR1–DR3). A fine primary pointer keeps today's motion (`spec:AST-094` FR19). | proposed from measured iOS 26.2 behavior | owner review | | ||
| | FR7 | Under a touch presentation, pointer input to the alert is held while it enters, through the layer runtime's shared input hold (`spec:AST-094` FR35); keyboard and assistive-technology input are never held, and the entrance never makes the content inert. While the alert leaves, its content is inert for the dismissal fade. The hold's timing stays internal (`spec:AST-002` FR3). | `spec:AST-094` FR35; owner decision (DEC-1) | decided | |
There was a problem hiding this comment.
No current architecture record or shipped code defines a layer-runtime input hold yet: architecture:layer-runtime INV14 lists none, and #8342 proposes it. architecture:knowledge-contracts INV18 keeps internal mechanisms out of component requirements. Suggest dropping "through the layer runtime's shared input hold", since spec:AST-094 FR35 already states the observable rule.
| | FR6 | Under a touch presentation (`spec:AST-094` FR13), a modal AlertDialog presents by scaling from 1.2 to 1 with its opacity and its backdrop's dimming rising from 0 to 1 on the motion role `springs.alertPresent`, started at the browser's commit, with the larger start kept inside the viewport; it dismisses by a fade alone on `springs.alertDismiss` and closes at the fade's end; a close during the presentation, or a reopen during the dismissal, springs from where it is. The roles are internal with UIKit's measured values (`spec:AST-094` FR4, DEC-11). Under Reduce Motion both are the shared cross-fade (`design:reduced-motion` DR1–DR3). A fine primary pointer keeps today's motion (`spec:AST-094` FR19). | proposed from measured iOS 26.2 behavior | owner review | | ||
| | FR7 | Under a touch presentation, pointer input to the alert is held while it enters, through the layer runtime's shared input hold (`spec:AST-094` FR35); keyboard and assistive-technology input are never held, and the entrance never makes the content inert. While the alert leaves, its content is inert for the dismissal fade. The hold's timing stays internal (`spec:AST-002` FR3). | `spec:AST-094` FR35; owner decision (DEC-1) | decided | | ||
| | FR8 | AlertDialog's actions are an action group (`family:action-groups`): a press that slides across them runs the action it lifts on, and a lift outside them runs nothing, under every pointer; keyboard and assistive-technology behavior is unchanged. | `family:action-groups`; `spec:AST-094` DEC-17 | decided | | ||
| | FR9 | On a phone, a compact width under a coarse primary pointer, the alert is 320 px wide in every theme, as iOS's is; no theme role sets it. Elsewhere it keeps today's width. | owner decision (DEC-2) | decided | |
There was a problem hiding this comment.
Please say whether an explicit width (default 400) still wins on a phone, and whether the 320 px stays within Dialog's viewport clamp below about 352 px. The Compatibility lines (59–65) and Contract at a glance still say nothing changes for builders; they should describe FR8's and FR9's effect.
|
/approve-spec ed49cce |
There was a problem hiding this comment.
Requesting changes: the engineering-owner approval settles this record's direction, but FR8 still rests on family:action-groups and spec:AST-094 DEC-17, which only exist in #8622, while current spec:AST-094 FR11 keeps a button's activation on the browser's click. Please land #8622 first and rebase so FR8 cites current text (then add FR8's decision and restate PR1), or move FR8 and its verification row to a follow-up. While you're there, mark FR6 as decided and list the touch presentation under the record's Ownership boundary.
[Automated review]
| | FR5 | `useImperativeAlertDialog` returns `show`, `hide`, and the element to render, and owns `isOpen`/`onOpenChange` for its caller. | shipped source and focused tests | verify | | ||
| | FR6 | Under a touch presentation (`spec:AST-094` FR13), a modal AlertDialog presents by scaling from 1.2 to 1 with its opacity and its backdrop's dimming rising from 0 to 1 on the motion role `springs.alertPresent`, started at the browser's commit, with the larger start kept inside the viewport; it dismisses by a fade alone on `springs.alertDismiss` and closes at the fade's end; a close during the presentation, or a reopen during the dismissal, springs from where it is. The roles are internal, with UIKit's measured values at `tempo` 1 and `'standard'`, and follow the theme's motion knobs (`spec:AST-094` FR4, DEC-15). Under Reduce Motion both are the shared cross-fade (`design:reduced-motion` DR1–DR3). A fine primary pointer keeps today's motion (`spec:AST-094` FR13 and its Non-goals). | proposed from measured iOS 26.2 behavior | owner review | | ||
| | FR7 | Under a touch presentation, pointer input to the alert is held while it enters (`spec:AST-094` FR35); keyboard and assistive-technology input are never held, and the entrance never makes the content inert. While the alert leaves, its content is inert for the dismissal fade. The hold's timing stays internal (`spec:AST-002` FR3). | `spec:AST-094` FR35; owner decision (DEC-1) | decided | | ||
| | FR8 | AlertDialog's actions are an action group (`family:action-groups`): a press that slides across them runs the action it lifts on, and a lift outside them runs nothing, under every pointer; keyboard and assistive-technology behavior is unchanged. | `family:action-groups`; `spec:AST-094` DEC-17 | decided | |
There was a problem hiding this comment.
FR8's Basis cites family:action-groups and spec:AST-094 DEC-17, which are not on main yet (both arrive with #8622). Current spec:AST-094 FR11 says a control's "activation stays the browser's click", and FR26–FR28 cover only useMenuPress surfaces, so FR8 contradicts current text. Land #8622 first and rebase (then add FR8's own decision and restate PR1, whose "only listener" sentence FR8's press tracking makes untrue), or move FR8 and its verification row to a follow-up.
| | FR3 | The anatomy is title, description, then the buttons: Cancel then action on wider screens, the action stacked above Cancel on small screens, Cancel keeping initial focus either way; the action may show a loading state while `isActionLoading`. | shipped source and focused tests | verify | | ||
| | FR4 | `isInline` renders the same anatomy without modality and without the alert-dialog role. | shipped source and public docs | verify | | ||
| | FR5 | `useImperativeAlertDialog` returns `show`, `hide`, and the element to render, and owns `isOpen`/`onOpenChange` for its caller. | shipped source and focused tests | verify | | ||
| | FR6 | Under a touch presentation (`spec:AST-094` FR13), a modal AlertDialog presents by scaling from 1.2 to 1 with its opacity and its backdrop's dimming rising from 0 to 1 on the motion role `springs.alertPresent`, started at the browser's commit, with the larger start kept inside the viewport; it dismisses by a fade alone on `springs.alertDismiss` and closes at the fade's end; a close during the presentation, or a reopen during the dismissal, springs from where it is. The roles are internal, with UIKit's measured values at `tempo` 1 and `'standard'`, and follow the theme's motion knobs (`spec:AST-094` FR4, DEC-15). Under Reduce Motion both are the shared cross-fade (`design:reduced-motion` DR1–DR3). A fine primary pointer keeps today's motion (`spec:AST-094` FR13 and its Non-goals). | proposed from measured iOS 26.2 behavior | owner review | |
There was a problem hiding this comment.
FR6's Draft review state still reads "owner review", although this head is owner-approved and FR7–FR9 read "decided".
| | FR6 | Under a touch presentation (`spec:AST-094` FR13), a modal AlertDialog presents by scaling from 1.2 to 1 with its opacity and its backdrop's dimming rising from 0 to 1 on the motion role `springs.alertPresent`, started at the browser's commit, with the larger start kept inside the viewport; it dismisses by a fade alone on `springs.alertDismiss` and closes at the fade's end; a close during the presentation, or a reopen during the dismissal, springs from where it is. The roles are internal, with UIKit's measured values at `tempo` 1 and `'standard'`, and follow the theme's motion knobs (`spec:AST-094` FR4, DEC-15). Under Reduce Motion both are the shared cross-fade (`design:reduced-motion` DR1–DR3). A fine primary pointer keeps today's motion (`spec:AST-094` FR13 and its Non-goals). | proposed from measured iOS 26.2 behavior | owner review | | ||
| | FR7 | Under a touch presentation, pointer input to the alert is held while it enters (`spec:AST-094` FR35); keyboard and assistive-technology input are never held, and the entrance never makes the content inert. While the alert leaves, its content is inert for the dismissal fade. The hold's timing stays internal (`spec:AST-002` FR3). | `spec:AST-094` FR35; owner decision (DEC-1) | decided | | ||
| | FR8 | AlertDialog's actions are an action group (`family:action-groups`): a press that slides across them runs the action it lifts on, and a lift outside them runs nothing, under every pointer; keyboard and assistive-technology behavior is unchanged. | `family:action-groups`; `spec:AST-094` DEC-17 | decided | | ||
| | FR9 | On a phone, a compact width under a coarse primary pointer, the alert is 320 px wide in every theme, as iOS's is; no theme role sets it. A caller's explicit `width` still wins there (`architecture:public-component-api` INV5), and Dialog's viewport clamp still applies on a screen narrower than the alert. Elsewhere it keeps today's width. | owner decision (DEC-2) | decided | |
There was a problem hiding this comment.
"a compact width" could be read as width alone; the shared definition is compact, width below md or height below 500 (spec:AST-012 FR9, architecture:public-component-api INV17). Citing it keeps a landscape phone unambiguous.
|
/approve-spec 2fbd091 |
There was a problem hiding this comment.
Requesting changes: an engineering owner approved this head's direction, and FR8 now rests on the current family:action-groups record and spec:AST-094 DEC-17, so one small record fix remains. Please update the Contract at a glance so End-user impact names what FR6–FR9 change for people (the phone motion and entrance hold, the 320 px phone width, and the slide that now runs the lifted action under every pointer, mouse included), and Governing rules lists spec:AST-094, family:action-groups, design:reduced-motion and spec:AST-017. While you're there, consider saying where focus sits during the dismissal fade, restoring None. under Open questions, and using the template's settled state.
[Automated review]
| @@ -39,8 +46,8 @@ system_specs: [spec:AST-020/FR15] | |||
| | Public contract | None changes. `AlertDialog`, `AlertDialogProps`, and `useImperativeAlertDialog` are exported from `@astryxdesign/core/AlertDialog`; `title`, `description`, `actionLabel`, `onAction`, and `onOpenChange` are required with `isOpen`, plus cancel label, action variant, loading, width, and an inline preview mode. | | |||
| | Behavior | A modal confirmation that interrupts: it opens through the native dialog, cannot be dismissed by a click outside, closes on Escape or Cancel through `onOpenChange(false)`, and runs `onAction` on the action button. | | |||
| | End-user impact | A keyboard or screen-reader user is told a decision is needed (the title and description are announced), lands on Cancel, and cannot lose the dialog by clicking past it. | | |||
There was a problem hiding this comment.
This row still describes only the keyboard and screen-reader baseline, while FR6–FR9 change what people meet: the phone motion and entrance hold, the 320 px phone width, and FR8's slide, which lets a mouse press that starts on Cancel run the destructive action. The template keeps Builder impact for migration and caller choices, so FR8's effect belongs here; Governing rules (line 52) should also list spec:AST-094, family:action-groups, design:reduced-motion and spec:AST-017.
| | FR4 | `isInline` renders the same anatomy without modality and without the alert-dialog role. | shipped source and public docs | verify | | ||
| | FR5 | `useImperativeAlertDialog` returns `show`, `hide`, and the element to render, and owns `isOpen`/`onOpenChange` for its caller. | shipped source and focused tests | verify | | ||
| | FR6 | Under a touch presentation (`spec:AST-094` FR13), a modal AlertDialog presents by scaling from 1.2 to 1 with its opacity and its backdrop's dimming rising from 0 to 1 on the motion role `springs.alertPresent`, started at the browser's commit, with the larger start kept inside the viewport; it dismisses by a fade alone on `springs.alertDismiss` and closes at the fade's end; a close during the presentation, or a reopen during the dismissal, springs from where it is. The roles are internal, with UIKit's measured values at `tempo` 1 and `'standard'`, and follow the theme's motion knobs (`spec:AST-094` FR4, DEC-15). Under Reduce Motion both are the shared cross-fade (`design:reduced-motion` DR1–DR3). A fine primary pointer keeps today's motion (`spec:AST-094` FR13 and its Non-goals). | proposed from measured iOS 26.2 behavior | decided | | ||
| | FR7 | Under a touch presentation, pointer input to the alert is held while it enters (`spec:AST-094` FR35); keyboard and assistive-technology input are never held, and the entrance never makes the content inert. While the alert leaves, its content is inert for the dismissal fade. The hold's timing stays internal (`spec:AST-002` FR3). | `spec:AST-094` FR35; owner decision (DEC-1) | decided | |
There was a problem hiding this comment.
Non-blocking: with the content inert for the fade and the dialog closing only at its end, focus leaves the pressed button for about 0.4 s before Dialog returns it to the opener. Consider stating where focus sits during the fade.
|
/approve-spec 8d58038 |
There was a problem hiding this comment.
Requesting changes: an engineering owner approved this revision's direction, and FR6–FR9 match the current touch-presentation, action-groups, reduced-motion and release records, so one small record fix remains. Under Ownership boundary, please move "its actions' membership in family:action-groups (FR8)" from Owns to Does not own (for example "A press that slides across the actions acts on the lifted one, as family:action-groups owns"), because that family record owns membership and the shared slide behavior, as ButtonGroup, Toolbar and Banner already record. While you're there, consider adding a fine-pointer state to the FR7 and FR9 verification rows, saying where focus sits during the fade-out, using the template's settled review state, and refreshing the title, which still mentions OQ1–OQ3.
[Automated review]
| - The touch presentation's motion, input hold, and phone width (FR6, FR7, FR9), | ||
| and its actions' membership in `family:action-groups` (FR8). |
There was a problem hiding this comment.
This clause claims an ownership family:action-groups holds: its Content boundary says "This file owns action-group membership and the shared press, slide, and lift behavior", and architecture:knowledge-contracts INV2 reads "One fact has one owner". ButtonGroup, Toolbar and Banner list the same thing under Does not own. Suggest dropping it here and adding under Does not own: "A press that slides across the actions acts on the lifted one, as family:action-groups owns (FR8)."
| | FR7 | Browser tests under a coarse pointer, with keyboard and assistive-technology input | a tap during the presentation, Enter and Escape during it, a screen reader's activation, a tap during the dismissal | a held key or assistive-technology action, content made inert during the entrance, or a tap that reaches a leaving alert fails | `audit:AlertDialog/behavior` | | ||
| | FR8 | Pointer-stream tests with a mouse, a pen, and a finger, and keyboard tests | a press on Cancel slid onto the action and lifted, and a press lifted outside the actions, each with a mouse, a pen, and a finger; Enter and Space on each action | the press-start action running after a slide, any action running on a lift outside, or a changed keyboard or assistive-technology activation fails | `audit:AlertDialog/behavior` | | ||
| | FR9 | Browser tests at a phone width and at a desktop width, in the default and an alternate theme | a phone width and a desktop width, in the default and an alternate theme; a caller `width` at a phone width; a screen narrower than 320 px | a phone-width alert other than 320 px in any theme without a caller `width`, a caller `width` overridden, a desktop width changed, or an alert wider than the viewport fails | `audit:AlertDialog/behavior` | |
There was a problem hiding this comment.
Non-blocking: neither the FR7 nor the FR9 row has a fine-pointer state. The FR9 row passes an alert keyed on viewport width alone (no narrow fine-pointer window, no coarse screen that is not compact), and the FR7 row passes a hold that also swallows a mouse click, although spec:AST-094 FR35 leaves a mouse unchanged. Adding those states lets the rows fail a pointer-blind implementation.
|
/approve-spec 67f1023 |
There was a problem hiding this comment.
Approving: an engineering owner approved this revision's direction, FR6–FR9 match the current touch-presentation, action-groups, reduced-motion and compatibility records, and the requested ownership fix is in. Whichever of this pull request and #8084 lands second should reconcile #8084's own FR6 width row and its presentation prop with this record. Two optional touches: say in FR7 where focus sits during the dismissal fade, and use the template's settled review state instead of decided.
[Automated review]
Her merged record (meta#8594) keeps AlertDialog's public contract unchanged: the touch presentation is a behavior change, and on a phone a caller's width is its way back (FR9). Pin AlertDialogProps so it has no presentation prop and keeps width. Fails typecheck while the prop exists.
…keeps the public contract Her merged AlertDialog record (meta#8594) changes behavior under a touch presentation without changing the public API: a caller's width is the way back on a phone (FR9), and no other prop is added. Remove the presentation prop, its AlertDialogPresentation type, the DialogPresentation story, its doc entry and the tests that used it. The width test also covers a caller's width on a phone.
…lertDismiss Her merged AlertDialog FR6 (meta#8594) names the alert's motion roles springs.alertPresent and springs.alertDismiss, the springs table's rows. Expect those role ids, the alert's two springs among the registered springs roles, and AlertDialog registering those two rows alone. Fails while the roles are registered as alert.present and alert.dismiss.
…d springs.alertDismiss Her merged AlertDialog FR6 (meta#8594) names the alert's motion roles by their springs table rows. Register the alert's two springs among the springs roles under those names, rename AST-094 FR4's two rows to match, and let AlertDialog register those two rows alone (registerAlertSprings), so its bundle still carries no other spring. The alert table keeps only its measured values. Same springs and timings; only the role ids change.
…he keyboard keeps the buttons Her AlertDialog record (meta#8594) verifies FR8 with a press lifted outside the actions under a mouse, a pen and a finger, and with Enter and Space on each action. Add the two cases the tests lacked: a mouse press that slides off both actions highlights nothing and runs nothing at the lift, and under a coarse and a fine pointer Enter runs the action and Space cancels. A mutant that stops tracking a mouse's moves fails the first; one that drops the buttons' own click fails the second.
Decided (Cindy, 2026-10-26: D30 = A, D31 = a, D32). FR7, FR8, and FR9 are decided; no open questions remain.
User impact
On a phone, AlertDialog today rises 16 px and grows from 95 % as it fades in, its dimming pops on, and it vanishes in one frame. A tap on an action during the entrance runs it. iOS's alert shrinks into place, holds touches while it appears, and fades out. This proposal records that touch presentation, as measured on the iOS 26.2 simulator in #8084, so the implementation has a record to follow.
Proposed requirements (draft
component:AlertDialog)springs.alertPresent, started at the browser's commit, with the larger start kept inside the viewport.springs.alertDismiss; the dialog closes at its end.spec:AST-094FR4, DEC-11), and become themeable once the public motion set exists. Reduce Motion gets the shared cross-fade (design:reduced-motion). A fine pointer keeps today's motion (spec:AST-094FR19).spec:AST-094FR35. Keyboard and assistive technology are never held, the entrance never makes content inert, and content is inert only during the dismissal fade.family:action-groupsmember. A press that slides across them runs the action it lifts on, and a lift outside runs nothing, under every pointer. Keyboard and AT are unchanged.::backdrop, withinspec:AST-017FR60's open-layer allowance.Notes for review
holdInput, feat(Layer): one input hold, first used by Dialog, Drawer and MobileNav (spec:AST-094 FR35) #8342). That's separate fromarchitecture:layer-runtimeINV14's presentation hold, which keeps a layer's chosen presentation until its close settles.Writing rubric results