Repository navigation
architecture(layer-runtime): one generic layer runtime, and one opt-in lift-from-trigger module (INV14, INV15) #8448
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c954a3c
59908d2
a6c1c58
22c91a1
fc07445
879ac03
c7a7f6c
7d37a76
d795cd8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -55,14 +55,25 @@ deciding_specs: [spec:AST-038, spec:AST-059] | |
| { | ||
| "scope": "global", | ||
| "triggers": { | ||
| "layering": ["INV2", "INV5", "INV6", "INV7", "INV11", "INV12"], | ||
| "layering": [ | ||
| "INV2", | ||
| "INV5", | ||
| "INV6", | ||
| "INV7", | ||
| "INV11", | ||
| "INV12", | ||
| "INV14", | ||
| "INV15" | ||
| ], | ||
| "layout": ["INV3", "INV11", "INV12"] | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| This record describes the layer runtime shipped on current `main`. Accepted but | ||
| unimplemented changes live in `spec:AST-003`; they are not current architecture. | ||
| This record describes the layer runtime shipped on current `main`, except | ||
| INV14 and INV15, which state required ownership the runtime does not yet meet; | ||
| Current gaps lists where it falls short. Other accepted but unimplemented | ||
| changes live in `spec:AST-003`; they are not current architecture. | ||
|
|
||
| ## Purpose | ||
|
|
||
|
|
@@ -439,6 +450,30 @@ layers use Layer rendering without joining Escape/platform dismissal. | |
| correct, and the runtime polls nothing: an anchor that a scrolled | ||
| container hides is followed again when an intersection observer reports it | ||
| back in view. | ||
| - **INV14 — The runtime owns every layer's shared mechanism.** Internally, the layer runtime owns the shared | ||
| mechanism layers use: top-layer mounting, close-request delivery, the | ||
| presentation hold (keeping a layer's chosen presentation from the open until | ||
| the close settles), the one shared exit copy (the single Core mechanism | ||
| `architecture:component-style-authoring` INV7 names), and the backdrop tint, | ||
| drawn with `::backdrop`. A component that needs one of these uses the | ||
| runtime's rather than building its own. Each component still decides when it | ||
| dismisses, how it is hosted, and how it is presented, including the | ||
| backdrop's color and every other visual treatment (INV9; | ||
| `family:overlay-dismissal` AV3, AV4, AV6; `spec:AST-003` FR10). The runtime's | ||
| public exports are unchanged. | ||
| - **INV15 — One lift-from-trigger module, opt-in per surface.** Lift-from-trigger presentation lives in one | ||
| internal module separate from the layer runtime: the lift from the trigger, | ||
| using the real trigger or a clone, whichever keeps the motion on the | ||
| compositor (`spec:AST-094` FR5); | ||
| the grow from the trigger's rectangle through the shared rectangle morph | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Optional clarification: say where the shared rectangle morph lives. Popover must grow from its trigger without lifting (Popover FR9, from the touch-presentations spec's FR31), INV15 keeps layers that do not lift out of this module, and the Verification row fails rectangle-morph code outside the runtime and the lift module, so the runtime is its only conforming home. |
||
| (one Core animation from one rectangle to another); and | ||
| the exit, played through the runtime's exit copy (INV14). A clone of the | ||
| trigger is the one transient copy `architecture:component-style-authoring` | ||
| INV7 allows: inert, hidden from assistive technology, and removed when the | ||
|
Comment on lines
+471
to
+472
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. component-style-authoring INV7 allows only one transient copy "during an exit, a presentation switch, or a handoff between sheets", made "by one Core mechanism that every layer uses". INV14 already names the runtime's exit copy as that mechanism, and this module is separate from the runtime and used only by lifting surfaces. Amend INV7 in this pull request to admit the lift clone, or keep the real trigger; "the performance outcomes" that choose between them are not defined anywhere. |
||
| lift settles. Surfaces opt in; | ||
| any surface that lifts uses this module and never its own copy, and layers | ||
| that do not lift do not use it. It is internal and unexported | ||
| (`spec:AST-017` FR21). | ||
|
|
||
| This record does not make future eligible-owner, branch-association, global-host, | ||
| or browser-support requirements current. It does not own component focus entry or | ||
|
|
@@ -468,6 +503,11 @@ Current gaps are observable facts, not current target behavior: | |
| migration, verification, and completion criteria for these gaps. This record must | ||
| be updated only as that work ships. | ||
|
|
||
| INV14 and INV15 are not met yet, and `spec:AST-003` does not cover them: no | ||
| shared presentation hold, exit copy, runtime backdrop tint, or lift module | ||
| exists, and Dialog, Drawer, BottomSheet, Lightbox, MobileNav, ToastViewport, | ||
| and Selector each build their own top-layer mounting, exit, or backdrop. | ||
|
|
||
| ## Change coupling | ||
|
|
||
| - A change to `useLayer` hosting or lifecycle verifies safe inline placement, | ||
|
|
@@ -557,16 +597,17 @@ this current architecture record. | |
|
|
||
| ## Verification | ||
|
|
||
| | Invariant | Evidence | Failure signal | | ||
| | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| | INV1, INV2 | `useLayer.test.tsx` and `layerHost.test.ts` | Invalid DOM, stale host, lost theme/writing context, or portal mistaken for top-layer promotion | | ||
| | INV3–INV5 | `useLayer.test.tsx` and `anchorName.test.ts` | A mode leaks geometry, RTL resolves from the wrong context, fallback clips, or a sibling anchor is lost | | ||
| | INV11 | `layerViewportInset.test.ts`, `useLayer.test.tsx`, and the `Core/Layer` viewport-inset stories under the story play guard at a desktop and a phone viewport | A second gutter definition, a `100%`-of-span cap, a layer narrower than its explicit size, a layer box wider than the viewport, a layer inside the gutter, or a layer that slides toward an off-screen anchor | | ||
| | INV12 | The `Core/Layer` viewport-inset stories' first-frame comparison, and `useLayer.test.tsx`'s synchronous anchor read | A layer whose first painted rectangle differs from its settled one | | ||
| | INV6, INV7 | `useLayer.test.tsx`, `Popover.test.tsx`, `DropdownMenu.test.tsx`, and `useMenuHover.test.tsx` | Duplicate close callback or the same press/re-hover reopens a surface | | ||
| | INV8 | `useLayerDismissal.test.tsx`, `layerDismissalInvariants.test.tsx`, and `useFocusTrap.test.tsx` | Current top registered layer is skipped, two layers close, or a blocker leaks through | | ||
| | INV9 | Representative Dialog, ContextMenu, Tooltip/HoverCard, and BottomSheet source/tests | A current local channel silently changes ownership or policy | | ||
| | INV10 | `LayerProvider.tsx`, `LayerProvider.test.tsx`, `useToast.tsx`, `ToastViewport.test.tsx`, and `ToastViewport.modalHost.test.tsx` | Provider begins relocating ordinary layers, Toast fallback loses its current lifecycle, or a default provider renders differently from no provider | | ||
| | Invariant | Evidence | Failure signal | | ||
| | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| | INV1, INV2 | `useLayer.test.tsx` and `layerHost.test.ts` | Invalid DOM, stale host, lost theme/writing context, or portal mistaken for top-layer promotion | | ||
| | INV3–INV5 | `useLayer.test.tsx` and `anchorName.test.ts` | A mode leaks geometry, RTL resolves from the wrong context, fallback clips, or a sibling anchor is lost | | ||
| | INV11 | `layerViewportInset.test.ts`, `useLayer.test.tsx`, and the `Core/Layer` viewport-inset stories under the story play guard at a desktop and a phone viewport | A second gutter definition, a `100%`-of-span cap, a layer narrower than its explicit size, a layer box wider than the viewport, a layer inside the gutter, or a layer that slides toward an off-screen anchor | | ||
| | INV12 | The `Core/Layer` viewport-inset stories' first-frame comparison, and `useLayer.test.tsx`'s synchronous anchor read | A layer whose first painted rectangle differs from its settled one | | ||
| | INV6, INV7 | `useLayer.test.tsx`, `Popover.test.tsx`, `DropdownMenu.test.tsx`, and `useMenuHover.test.tsx` | Duplicate close callback or the same press/re-hover reopens a surface | | ||
| | INV8 | `useLayerDismissal.test.tsx`, `layerDismissalInvariants.test.tsx`, and `useFocusTrap.test.tsx` | Current top registered layer is skipped, two layers close, or a blocker leaks through | | ||
| | INV9 | Representative Dialog, ContextMenu, Tooltip/HoverCard, and BottomSheet source/tests | A current local channel silently changes ownership or policy | | ||
| | INV10 | `LayerProvider.tsx`, `LayerProvider.test.tsx`, `useToast.tsx`, `ToastViewport.test.tsx`, and `ToastViewport.modalHost.test.tsx` | Provider begins relocating ordinary layers, Toast fallback loses its current lifecycle, or a default provider renders differently from no provider | | ||
| | INV14, INV15 | Source boundary check over Core for top-layer hosts, exit copies, backdrop elements, lift, and rectangle-morph code outside the runtime and the lift module | A component building its own copy of a mechanism INV14 lists (top-layer mounting, close-request delivery, hold, exit copy, or backdrop element), or re-implementing the lift or the grow | | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This failure signal is met by shipped code as soon as it merges: Dialog, Drawer, BottomSheet, Lightbox and MobileNav draw their own |
||
|
|
||
| Current unit coverage proves emitted styles, reducers, state transitions, and DOM | ||
| placement. Native Popover, `<dialog>`, focus, top-layer ordering, and rendered | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The runtime now owns the backdrop tint and top-layer mounting, but the overlay-dismissal family's AV6 ("Members own animation, visual treatment, and theming anatomy"), this record's boundary sentence ("It does not own ... visual treatment") and its Owning code ("Dialog families own native modal/backdrop presentation"; "Drawer owns modal
showModal()and non-modalshowPopover()hosting") still give those to components. Except the runtime's tint and mounting there, or narrow this claim.