Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
268b63f
architecture(react-component-runtime): proposed: one disclosure-heigh…
cixzhang Oct 25, 2026
ffc8c07
architecture(react-component-runtime): INV12's internal usage shape
cixzhang Oct 25, 2026
0c3e730
architecture(react-component-runtime): INV12 handle decided: any cont…
cixzhang Oct 26, 2026
2d8d278
architecture(react-component-runtime): INV12 mixed following content …
cixzhang Oct 26, 2026
c90ea1c
architecture(react-component-runtime): INV12 defers Reduce Motion to …
cixzhang Oct 26, 2026
efadb04
architecture(react-component-runtime): OQ2 drops the wrapper option; …
cixzhang Oct 26, 2026
1e6a757
architecture(react-component-runtime): INV12's bounded ancestor-and-s…
cixzhang Oct 26, 2026
322a9d6
architecture(react-component-runtime): INV12 is a general size-change…
cixzhang Oct 26, 2026
7a4abcb
architecture(react-component-runtime): INV12 names the walk's traversal
cixzhang Oct 26, 2026
7ebe8cd
architecture(react-component-runtime): INV12 says what the hook does …
cixzhang Oct 26, 2026
ecc40ab
architecture(react-component-runtime): INV12's element-selection rule…
cixzhang Oct 26, 2026
7534a6e
architecture(react-component-runtime): INV12's element-selection rule…
cixzhang Oct 26, 2026
8e6a367
architecture(react-component-runtime): INV12 animates only changed el…
cixzhang Oct 26, 2026
22d7a04
architecture(react-component-runtime): INV12's coverage table and out…
cixzhang Oct 26, 2026
ea8086f
architecture(react-component-runtime): coverage for inline lines, fle…
cixzhang Oct 26, 2026
8ba07c8
architecture(react-component-runtime): coverage: unstuck sticky moves…
cixzhang Oct 26, 2026
a28eeed
architecture(react-component-runtime): OQ4 names from the vibe test; …
cixzhang Oct 26, 2026
476f482
architecture(react-component-runtime): INV12 uses OQ4's recommended name
cixzhang Oct 26, 2026
f072779
architecture(react-component-runtime): the hook is useAnimatedLayout …
cixzhang Oct 26, 2026
2a86773
architecture(react-component-runtime): the changed element animates i…
cixzhang Oct 26, 2026
0266a3b
architecture(react-component-runtime): every-pointer scope decided, a…
cixzhang Oct 26, 2026
163bef4
architecture(react-component-runtime): the area owns the shared timin…
cixzhang Oct 26, 2026
6e75feb
architecture(react-component-runtime): INV12 decided by cixzhang; no …
cixzhang Oct 26, 2026
e8da4fb
architecture(react-component-runtime): one shared motion role for the…
cixzhang Oct 26, 2026
f7315cd
architecture(react-component-runtime): useAnimatedLayout({containerRe…
cixzhang Oct 26, 2026
4d61826
architecture(react-component-runtime): nested areas follow the handle
cixzhang Oct 26, 2026
14155a2
architecture(react-component-runtime): handle stays member-free; scro…
cixzhang Oct 26, 2026
5374442
architecture(react-component-runtime): springs.settle until the schem…
cixzhang Oct 26, 2026
6fc2ce0
architecture(react-component-runtime): System model admits the glide;…
cixzhang Oct 26, 2026
1761e73
architecture(react-component-runtime): INV12's no-handle behavior and…
cixzhang Oct 26, 2026
c3d4e45
spec(AST-105): the animated-layout public contract moves into a syste…
cixzhang Oct 26, 2026
879f50e
spec(AST-105): the motion role is not themeable yet (AST-094 DEC-11)
cixzhang Oct 26, 2026
0c0c8f4
spec(AST-105): observable wording, ScrollableArea label, consumer doc…
cixzhang Oct 26, 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
43 changes: 31 additions & 12 deletions docs/architecture/react-component-runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ verified_by:
packages/core/src/Layer/useLayer.test.tsx,
packages/core/src/utils/sharedResizeObserver.test.ts,
]
deciding_specs: [spec:AST-086/DEC-2, spec:AST-099/DEC-1]
deciding_specs: [spec:AST-086/DEC-2, spec:AST-099/DEC-1, spec:AST-105/DEC-1]
---

# React component runtime architecture
Expand All @@ -35,7 +35,8 @@ deciding_specs: [spec:AST-086/DEC-2, spec:AST-099/DEC-1]
"INV6",
"INV8",
"INV10",
"INV11"
"INV11",
"INV12"
]
}
}
Expand Down Expand Up @@ -158,6 +159,21 @@ those contracts.
does, blurs as FR5 does, applies the height through a functional style on
its own elements, and follows INV3 and INV5. The hook follows INV3 and
INV5.
- **INV12 — Size changes inside a container have one module.** In
`@astryxdesign/core`, one internal module produces the size-change glide
`spec:AST-105` defines. It measures the layout before and after a reported
change and moves shifted content with a compositor-only translate played
through the shared rectangle morph (`architecture:layer-runtime` INV15;
`spec:AST-094` FR5); it never animates height. Its walk visits only the
following element siblings at each ancestor level up to the area, through
`parentElement` and `nextElementSibling`, descending only into an element
with `display: contents`, so its cost grows with depth plus following
siblings. Changes in one area in the same frame are measured together. A
component reports a change through an internal, non-exported function that
takes the `useAnimatedLayout` handle, so the handle stays member-free, and
each moving element is one the page already renders
(`architecture:component-style-authoring` INV7). The module follows INV3
and INV5.

## Authoring guidance

Expand Down Expand Up @@ -279,6 +295,8 @@ contracts.
component that announces its own rendered content (INV10).
- `spec:AST-099/DEC-1` — one keyboard height for every component, kept
internal and applied through functional styles (INV11).
- `spec:AST-105/DEC-1` — the size-change glide's public shape and behavior

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The frontmatter deciding_specs (line 18) still lists only spec:AST-086/DEC-2 and spec:AST-099/DEC-1, so pnpm specs:for does not report spec:AST-105/DEC-1 as a decision for Core paths; add it there too.

(INV12).

Component, family, API, accessibility, layer, interaction, and style records
remain authoritative for the other user-facing outcomes delegated above.
Expand All @@ -292,13 +310,14 @@ observable-behavior predicates require review or runtime evidence. Likewise, a
focused test proves only its named behavior and mutation expectation; a green
component suite is not blanket conformance with every invariant.

| Invariant | Evidence | Failure signal |
| ---------------- | -------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| INV1–INV2 | Initial-render and interaction tests | Output flashes a known-wrong state, or one action is delayed or repeated through an Effect |
| INV3, INV5 | StrictMode setup/cleanup and dependency-change tests | Duplicate callback, leaked work, stale subscription, or missing resynchronization |
| INV1, INV4, INV6 | Ref attach/null/replacement, DOM-in-state rejection, and old-node cleanup-before-new-attach mutations | A DOM node or collection enters state, old node remains active, cleanup misses replacement, or ref mutation changes semantics silently |
| INV7 | Real-browser geometry plus N-consumer observer-instance/subscription mutations | Geometry is invalid, observer instances grow with repeated consumers, one unsubscribe silences peers, or cleanup removes another subscriber |
| INV8 | Owner-observable behavior across documented composition replacement; optional focused internal mechanism tests | Behavior disappears or changes owner when a documented subpart is replaced |
| INV9 | Provider/external-store identity and render-count tests | Unchanged semantic payload changes identity, or snapshot identity creates a render loop |
| INV10 | Shared test over every adopter of the announcement module | An adopter holding its own Effect, observer, timer, or listener for its own-content announcement |
| 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 Core rider driven by JavaScript per frame or by its own transition; or more than one layout read per keyboard change |
| Invariant | Evidence | Failure signal |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| INV1–INV2 | Initial-render and interaction tests | Output flashes a known-wrong state, or one action is delayed or repeated through an Effect |
| INV3, INV5 | StrictMode setup/cleanup and dependency-change tests | Duplicate callback, leaked work, stale subscription, or missing resynchronization |
| INV1, INV4, INV6 | Ref attach/null/replacement, DOM-in-state rejection, and old-node cleanup-before-new-attach mutations | A DOM node or collection enters state, old node remains active, cleanup misses replacement, or ref mutation changes semantics silently |
| INV7 | Real-browser geometry plus N-consumer observer-instance/subscription mutations | Geometry is invalid, observer instances grow with repeated consumers, one unsubscribe silences peers, or cleanup removes another subscriber |
| INV8 | Owner-observable behavior across documented composition replacement; optional focused internal mechanism tests | Behavior disappears or changes owner when a documented subpart is replaced |
| INV9 | Provider/external-store identity and render-count tests | Unchanged semantic payload changes identity, or snapshot identity creates a render loop |
| INV10 | Shared test over every adopter of the announcement module | An adopter holding its own Effect, observer, timer, or listener for its own-content announcement |
| 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 Core rider driven by JavaScript per frame or by its own transition; or more than one layout read per keyboard change |
| 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, or an exported reporting function fails |
Loading
Loading