ProjectionSystem: its internal types
Interfaces
ProjectionSink
What the engine writes each node's projection through: a FlushGate is one, so the engine never
imports a framework. write merges an element's projection into what it draws at the next frame;
flushPass runs a measure now, and draws what it wrote before it returns, so a new layout never paints
without its projection.
Properties
flushPass
readonly flushPass: (pass) => void;Runs pass, a measure, now, and draws what it wrote before it returns.
Parameters
pass
() => void
Returns
void
write
readonly write: (id, partial) => void;Merges partial into element id's values, drawn at the next frame.
Parameters
id
string
partial
Record<string, unknown>
Returns
void
ProjectionSystem
The Projection system: what a binding registers its layout elements with, one per provider.
Extends
Inspectable
Properties
animateLayout
readonly animateLayout: <A>(fn, options?) => A;A Declared layout change: run fn, and animate the layout change it makes from where every node
is at the call, even where no trigger sees the change or a node's last Measurement is out of date.
Returns fn's result; its error throws to the caller.
- The Measurements. The first call in a task measures every node before
fnruns. A Measure pass already due in the task runs then instead, so what triggered it animates as before, and its reads are the Measurements. Later calls in the task share them, so a node one call's change pushes animates from before the first change (Motion'sparallel-calls-intersecting). - The pass. The Measure pass at the end of the task animates every node that moved from those
Measurements. A running animation
fnmoves restarts from where it paints; one it doesn't move carries on. - What stays as in any pass. A Resize block wins:
fnruns and nothing animates. A dragged subtree takes its slot-only update. A call from inside a pass's own flush uses the reads that pass just made. - Synchronous only. A promise
fnreturns isn't awaited: a change after anawaitis in a later task. Such a call logs a warning. onSettledis called once the change has settled: every layout animation the end-of-task pass started has ended, however each ended (landed, cut short by a resize or an unmount, or restarted by a later change), or at the end of that pass if it started none. Calls in one task share that pass, so they settle together.
Type Parameters
A
A
Parameters
fn
() => A
options?
Returns
A
awaitsTwin
readonly awaitsTwin: (el) => boolean;Whether a twin that el is, or holds, left in this task with no live twin in its stack yet: a twin
arriving later in the same update takes it over, so a presence decides on el's leave at the task's
end, when handleLeave or handBackWithin finds that twin.
Parameters
el
HTMLElement
Returns
boolean
dispose
readonly dispose: () => void;Stops the engine: its run, its observers and its listeners. The Layer's Scope calls it.
Returns
void
dropLeaver
readonly dropLeaver: (el) => Option<number>;End a leaving Follower at once: a keyed presence child is back while its twin crossfades out, and
takes over. Its onDone is called, as at its handover's end. Returns the crossfade factor it had
faded to, for the child's new node to go on from (RegisterNodeOptions.fadeFrom); None for
an element that isn't one.
Parameters
el
HTMLElement
Returns
Option<number>
handBackWithin
readonly handBackWithin: (el, onDone) => Option<() => void>;Hand back the twins inside a leaving element that isn't a twin, for a presence child handleLeave declined: each crossfades onto its other twin, following the leaver's own exit.
onDone once every handover has ended; the returned call drops them at once. None when it held
none, so presence runs its exit alone.
Parameters
el
HTMLElement
onDone
() => void
Returns
Option<() => void>
handleLeave
readonly handleLeave: (el, onDone) => boolean;A leaving layoutId element its exit keeps in the document: true when there's a live twin, the
lead, to crossfade toward. The engine then draws el as a leaving follower, on the lead's box and
fading out, through the renderer since its gate is gone, and calls onDone once the crossfade settles,
so the exit removes it. false for one with no twin: its own exit runs as usual.
Parameters
el
HTMLElement
onDone
() => void
Returns
boolean
instant
readonly instant: (fn?) => void;An Instant change (Motion's useInstantLayoutTransition): run fn, and the Measure pass at the
end of the task gives every node its new box and starts nothing, as a Resize block's does. Every
running layout animation but a dragged node's ends on its slot as that pass begins.
Parameters
fn?
() => void
Returns
void
keepLeaving
readonly keepLeaving: (el, taken) => () => void;A presence child leaving with nobody to take its twins over: the twins it held as it went, inside it
or it a twin itself, stay a later twin's to take over while it's on the page, until the returned
call: the presence removing it, which ends their records at once (a held leaver otherwise lasts
until a task ends with it off the page). A twin that registers meanwhile brings one back as its
leaving Follower, as if it were live in its stack, and tells the presence through taken (LateTaken), which holds the child for that handover.
Its layout nodes with no layoutId, it included, come back as nodes it carries: corrected for an
ancestor's layout animation while it exits, its exit's own values drawn on the correction, and gone
with the returned call.
Parameters
el
HTMLElement
taken
Returns
() => void
keepSeen
readonly keepSeen: (el, move) => void;A leaver its presence popped out of the flow: at the first frame after, if the page scrolled since
(a router's scroll to the top at a navigation), move takes it by that scroll, so it stays where it
was seen, and the leaving nodes inside it go with it. Once: scrolling after moves it with the page.
Parameters
el
HTMLElement
move
(by) => void
Returns
void
notify
readonly notify: () => void;Asks for a measure of the whole tree at the end of the task, however many ask: for a change a group
declares, as a layout group's layoutDependency does, so every node its change moves animates.
Returns
void
onPassEnd
readonly onPassEnd: (listener) => () => void;Run listener at the end of every Measure pass; returns the unsubscribe. The engine's Layer hands
it out as the internal PassEnds service, beside the engine, not on it (internal/pass-ends.ts).
Parameters
listener
() => void
Returns
() => void
register
readonly register: (opts) => NodeHandle;Registers a layout element: its node, from then on measured at each layout change and animated from
where it was. The handle tells the engine what changed, and its dispose removes the node.
Parameters
opts
Returns
registerValues
readonly registerValues: (el, read) => () => void;Register an element's values: a binding hands every element's, read from what it last wrote, so a
layoutId twin's flight follows the translate and scale Wardic animates on its ancestors each
frame, an element that isn't a projection node included. A presence registers a leaver's drawn
values in their place, its Transform template among them, so it's drawn through it as it leaves.
Returns the unregistration, for the element's dispose.
Parameters
el
Element
read
() => Readonly<Record<string, unknown>>
Returns
() => void
reset
readonly reset: () => void;A Projection reset (Motion's useResetProjection): every running layout animation and Release
offset ends on its slot, every leaver and Switch seed goes (each layoutId stack keeps its live
nodes), and the next Measure pass measures every box afresh, animating none.
Returns
void
rootBoxOf
readonly rootBoxOf: (el) => Option<Box>;An element's box in the Root frame as it paints now, its transforms included: where a presence
child taking over from it starts (RegisterNodeOptions.enteredFrom). None for one off the
page.
Parameters
el
HTMLElement
Returns
Option<Box>
toJSON
readonly toJSON: () => Tree;The tree as plain data, for a diagnostic read: every node now, in the order it was registered.
console.log(system) shows it (Effect's Inspectable). Parent links are the last Measure pass's,
as the engine reads them.
Returns
Overrides
Inspectable.Inspectable.toJSON
ProjectionSystemOptions
What a binding hands its engine.
Properties
reducedMotion?
readonly reducedMotion?: () => boolean;Whether reduced motion applies now, read when a layout animation starts: the binding's
ReducedMotion.applies of its app's setting and the user's preference. Under it, a layout animation
lands on its new box at once, and a crossfade switches at once; a drag's release still returns to
its slot, since it continues the gesture (as Motion's does). By default, never.
Returns
boolean
scaleCorrectors?
readonly scaleCorrectors?: Readonly<Record<string, ScaleCorrector>>;The app's own scale correctors (Motion's addScaleCorrector entries), by the value key each
corrects, for this system's nodes alone. Each is handed the element's own value for its key each
frame (from its style or an animation), else its computed value read at its first Measurement, and
writes nothing while the projection doesn't scale it, putting the value back once. One keyed
borderRadius or boxShadow replaces the built-in one, and a replaced radius isn't blended across
a handover.
Type Aliases
LateTaken
type LateTaken = (drop) => () => void;A late take-over of a twin inside a leaving presence child, told to its presence, with drop to end
the handover at once. Returns what ends it as one of the child's parts.
Parameters
drop
() => void
Returns
() => void
ProjectionServices
type ProjectionServices =
| FrameLoop.FrameLoop
| Renderer.Renderer
| Probe.Probe
| AtomRegistry.AtomRegistry;What the engine needs from its Environment: the Frame loop it runs on, the renderer, which draws a
leaving follower whose gate is gone, and the Probe's viewport, read through the Environment's
AtomRegistry, so it lands rather than animates through a resize.