Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
a8a805b
spec(AST-094): gesture-driven motion plays a spring on every pointer
cixzhang Nov 3, 2026
25af4a1
spec(AST-094): list the motion FR44 moves, by component
cixzhang Nov 3, 2026
748cb56
spec(AST-094): number the gesture motion rule FR45, since FR44 is taken
cixzhang Nov 3, 2026
b9decfd
Merge main into spec/gesture-motion-springs; keep touch exits as they…
cixzhang Nov 3, 2026
4a89431
spec(AST-094): name the two approved springs FR45 keeps, use the them…
cixzhang Nov 3, 2026
22e080d
spec(AST-090, AST-094): a touch exit a tap, key or program starts pla…
cixzhang Nov 3, 2026
5aa0e0f
spec(AST-094): name the animator's animate among the kept springs, an…
cixzhang Nov 3, 2026
c3c695b
spec(AST-094, AST-090): exempt Reduce Motion substitutions and busy l…
cixzhang Nov 3, 2026
6a8960b
Merge main into spec/gesture-motion-springs; keep AlertDialog's touch…
cixzhang Nov 3, 2026
e540dba
spec: the animator's value mode follows its channels' timing; fix Pro…
cixzhang Nov 3, 2026
11f209e
spec: INV15's check follows its channels' timing; AlertDialog and Swi…
cixzhang Nov 3, 2026
47ab836
Merge main into spec/gesture-motion-springs; tap-started touch exits,…
cixzhang Nov 4, 2026
ebb5dbf
spec(AST-057, AST-090): a swipe row's tap or Escape close plays the t…
cixzhang Nov 4, 2026
630b9f0
Merge remote-tracking branch 'origin/main' into spec/gesture-motion-s…
cixzhang Nov 4, 2026
7ae648a
spec(AST-057): format
cixzhang Nov 4, 2026
6ea73c7
Merge remote-tracking branch 'origin/main' into spec/gesture-motion-s…
cixzhang Nov 4, 2026
3eb7fad
Merge remote-tracking branch 'origin/main' into spec/gesture-motion-s…
cixzhang Nov 4, 2026
7fc3273
Merge remote-tracking branch 'origin/main' into spec/gesture-motion-s…
cixzhang Nov 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions docs/architecture/react-component-runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -321,8 +321,7 @@ those contracts.
lockstep with Core, and limited by lint to Core and Lab (`spec:AST-017`
FR21).
- **INV15 — The animator animates a number.** The animator has a value mode:
it plays a number, such as a count or a chart value, on the same springs and
motion roles as its property channels, and hands the value to an `onUpdate`
it plays a number, such as a count or a chart value, on the same timing as its property channels: theme motion tokens for a program-started change, and measured springs only where `spec:AST-094` FR45 keeps them, and hands the value to an `onUpdate`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This now counts a program-started number on the theme's motion tokens, but the INV15 verification row (line 486) still fails "A value off its motion role", and theme tokens are not a motion role. Reword that failure to match, for example: "a value off its channels' timing (the theme's tokens for a program-started change, a spring only where spec:AST-094 FR45 keeps one)".

callback each frame for the component to format and write. The component owns
the change size past which it swaps to the new value instead of counting, so
a jump from twelve to over a million does not spin. Under reduced motion the
Expand Down Expand Up @@ -514,6 +513,6 @@ component suite is not blanket conformance with every invariant.
| INV11 | Source boundary check plus hook tests across StrictMode replay and unmount | A second keyboard listener or measurement in Core; a consumer reading a CSS custom property on the root or a shared ancestor for the height; an export of the hook; a component outside Core measuring by a rule other than AST-099 FR2, or riding the keyboard; a listener left after unmount; a translate left on an app element after the keyboard hides once focus has left the field, or after the field unmounts; any other write on an app element; a translate on a container whose layout box is not at the bottom edge, that fills the viewport, or whose own `translate` is not `none`; a translate on a container whose position the app is animating with CSS when the module measures; on a docked container too tall to fit above the keyboard once moved (a full-height side drawer, a pane below a fixed header), a translate when a scroller holds the field or one larger than the focused field needs to clear the keyboard; a translate measured before the page's own keyboard listeners run; a covered field deciding its keyboard behavior in an Effect that reacts to focus; a Core rider driven by JavaScript per frame or by its own transition; or more than one layout read per keyboard change beyond the docked bar's one read INV11 names |
| INV12 | Source boundary check plus real-browser tests on a throttled phone profile over a 10-level by 50-sibling tree and two changes in one frame | A per-frame height or layout, a walk past the area or into a subtree other than `display: contents`, an element moved twice for one frame, an added element other than a swap's one transient copy, that copy left after the swap ends, or an exported reporting function fails |
| INV13 | Source boundary check plus bundle analysis of a page with several touch components, and real-browser tests on a throttled phone profile, under a fine pointer, and on a hybrid device | A second copy of a touch module on one page, a component bundling its own copy of a module's primitive, an `import()` of a module in a component other than `Item`'s released loader for its deprecated swipe props, a swipe module (the gesture core, the animator, the panels' rendering, the row's gesture code) imported by `Item` or `ListItem`, swipe code in `Item` other than its deprecated path (that loader, the released row style, the role gate, the `commit` warning, the bridge, the click guard, the event forwarders, and the coexistence diagnostic), or any of it outside the deprecated path, a public export or doc entry for the modules, an install call or installed check in the public API, a gesture listener in a component that uses no gesture, or an idle document listener outside a press other than the one shared press controller and the one stray-click swallower, an import of `@astryxdesign/core/internal/*` outside Core and Lab, a class outside the recognizer family, an `instanceof` check on a recognizer, an internal factory with a public factory's name, or a direct module import for a job the public layer covers fails |
| INV15 | Unit tests of the animator's value mode and real-browser proofs of its adopters | A value off its motion role, a count past the component's swap size, a count or cross-fade under reduced motion with a coarse or a fine pointer, an intermediate value announced, or a public export fails |
| INV15 | Unit tests of the animator's value mode and real-browser proofs of its adopters | A value off its channels' timing (the theme's tokens for a program-started change, a spring only where `spec:AST-094` FR45 keeps one), a count past the component's swap size, a count or cross-fade under reduced motion with a coarse or a fine pointer, an intermediate value announced, or a public export fails |
| INV16 | Review of each Core component that handles a concern Core owns in a shared hook or utility | A Core component that keeps its own effect, listener, or tracker for that concern fails, whether or not it also calls the hook or utility |
| INV16 (slot presence) | `no-nullish-jsx-guard` strict lint over Core and RichText, with no baseline, and `no-truthy-jsx-guard` strict lint over Core, with no baseline; both catch inline guards only, so review also checks for a presence test hoisted into a variable, converted (`!!value`, `Boolean(value)`), made by an early return or a `??` default, or passed through a prop spread, which the lints pass; empty-slot tests that pass `''`, `false`, `true`, and `null` and compare with an omitted slot, plus `0` as content, in Item, MetadataList, ChatSystemMessage, TreeList, TopNavMegaMenu, RichTextEditor, and RichTextEditorToolbar | A slot given `''`, `true`, or `false` draws a wrapper, lane, border, or separator that an omitted slot does not, an element loses the name it has without the slot, `0` does not render, or a new bare nullish or truthiness presence test, inline or hoisted, a truthiness guard past the baseline, a baseline entry added, or a hand-written copy of the check lands |
Loading
Loading