@flemo/core 1.30.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/core/createRouterScope.d.ts +1 -0
  2. package/dist/core/engine/__tests__/createSwipeController.dragHooks.test.d.ts +1 -0
  3. package/dist/core/engine/__tests__/createSwipeController.dragProgress.test.d.ts +1 -0
  4. package/dist/core/engine/__tests__/createSwipeController.forcedCancel.test.d.ts +1 -0
  5. package/dist/core/engine/__tests__/createSwipeController.layerRelease.test.d.ts +1 -0
  6. package/dist/core/engine/__tests__/createSwipeController.nativeDrag.test.d.ts +1 -0
  7. package/dist/core/engine/__tests__/createSwipeController.rideOffset.test.d.ts +1 -0
  8. package/dist/core/engine/__tests__/layerRiders.test.d.ts +1 -0
  9. package/dist/core/engine/__tests__/variantStub.d.ts +13 -0
  10. package/dist/core/engine/createSwipeController.d.ts +5 -0
  11. package/dist/core/engine/diagnosticFlags.d.ts +1 -0
  12. package/dist/core/engine/flightRouting.d.ts +21 -0
  13. package/dist/core/engine/layerRiders.d.ts +21 -0
  14. package/dist/core/engine/types.d.ts +1 -0
  15. package/dist/dom/__tests__/stacking.test.d.ts +1 -0
  16. package/dist/dom/attributes.d.ts +126 -2
  17. package/dist/dom/stacking.d.ts +28 -0
  18. package/dist/history/createHistorySync.d.ts +2 -0
  19. package/dist/history/store.d.ts +0 -1
  20. package/dist/index.d.ts +16 -1
  21. package/dist/index.mjs +2577 -1274
  22. package/dist/morph/__tests__/attachMorph.test.d.ts +1 -0
  23. package/dist/morph/__tests__/morphAnimations.test.d.ts +1 -0
  24. package/dist/morph/__tests__/morphClip.test.d.ts +1 -0
  25. package/dist/morph/__tests__/morphGeometry.test.d.ts +1 -0
  26. package/dist/morph/__tests__/morphKeyframes.test.d.ts +1 -0
  27. package/dist/morph/__tests__/morphLayer.test.d.ts +1 -0
  28. package/dist/morph/__tests__/morphPaint.test.d.ts +1 -0
  29. package/dist/morph/__tests__/morphPose.test.d.ts +1 -0
  30. package/dist/morph/__tests__/morphSheet.test.d.ts +1 -0
  31. package/dist/morph/__tests__/morphSide.test.d.ts +1 -0
  32. package/dist/morph/__tests__/morphSwipe.test.d.ts +1 -0
  33. package/dist/morph/attachMorph.d.ts +73 -0
  34. package/dist/morph/morphAnimations.d.ts +2 -0
  35. package/dist/morph/morphClip.d.ts +31 -0
  36. package/dist/morph/morphGeometry.d.ts +111 -0
  37. package/dist/morph/morphKeyframes.d.ts +190 -0
  38. package/dist/morph/morphLayer.d.ts +14 -0
  39. package/dist/morph/morphPaint.d.ts +31 -0
  40. package/dist/morph/morphPose.d.ts +44 -0
  41. package/dist/morph/morphSheet.d.ts +9 -0
  42. package/dist/morph/morphSide.d.ts +43 -0
  43. package/dist/morph/morphSwipe.d.ts +24 -0
  44. package/dist/navigate/createNavigationController.d.ts +0 -1
  45. package/dist/screen/__tests__/publishRideBox.test.d.ts +1 -0
  46. package/dist/screen/publishRideBox.d.ts +1 -0
  47. package/dist/transition/__tests__/compileTransitionStyles.test.d.ts +2 -0
  48. package/dist/transition/__tests__/rideOffset.test.d.ts +1 -0
  49. package/dist/transition/compileTransitionStyles.d.ts +2 -1
  50. package/dist/transition/cubicBezier.d.ts +17 -0
  51. package/dist/transition/decorator/__tests__/resolveDecoratorClock.test.d.ts +14 -0
  52. package/dist/transition/decorator/createDecorator.d.ts +4 -5
  53. package/dist/transition/decorator/createRawDecorator.d.ts +10 -11
  54. package/dist/transition/decorator/resolveDecoratorClock.d.ts +36 -0
  55. package/dist/transition/decorator/typing.d.ts +8 -2
  56. package/dist/transition/morphTransition/__tests__/createMorphTransition.test.d.ts +1 -0
  57. package/dist/transition/morphTransition/createMorphTransition.d.ts +13 -0
  58. package/dist/transition/morphTransition/createRawMorphTransition.d.ts +17 -0
  59. package/dist/transition/morphTransition/morphTransition.d.ts +2 -0
  60. package/dist/transition/morphTransition/shared.d.ts +2 -0
  61. package/dist/transition/morphTransition/text.d.ts +2 -0
  62. package/dist/transition/morphTransition/typing.d.ts +72 -0
  63. package/dist/transition/morphTransition/zoom.d.ts +2 -0
  64. package/dist/transition/registerTransitionDefinitions.d.ts +2 -1
  65. package/dist/transition/rideOffset.d.ts +5 -0
  66. package/dist/transition/swipeSettle.d.ts +5 -1
  67. package/dist/transition/typing.d.ts +12 -1
  68. package/package.json +7 -7
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,73 @@
1
+ import { NavigateStatus, NavigateStoreApi } from '../navigate/store';
2
+ import { AnimationOptions } from '../transition/cssTypes';
3
+ import { MorphTransitionName } from '../transition/morphTransition/typing';
4
+ export interface AttachMorphOptions {
5
+ /** The pairing key. Two elements sharing it across a flight are one thing moving. */
6
+ layoutId: string | number;
7
+ /** A registered morph transition. Defaults to the built-in `shared` preset. */
8
+ name?: MorphTransitionName;
9
+ /** The navigate store of the Router scope this element belongs to. */
10
+ navigateStore: NavigateStoreApi;
11
+ }
12
+ interface MorphFlight {
13
+ finish: () => void;
14
+ /** The element in the air, so a morph nested inside it can find its clock. */
15
+ element: HTMLElement;
16
+ duration: number;
17
+ start: number;
18
+ ease: AnimationOptions["ease"];
19
+ /**
20
+ * Put the landing's safety net away, and set it again.
21
+ *
22
+ * A flight lands on its travel's own `animationend`, and the backstop exists
23
+ * for the ones that never get one — a screen frozen mid-air, a tab
24
+ * backgrounded before the compositor reports back. It is armed for the
25
+ * flight's own length, which is the right guess for a flight on a clock and
26
+ * the wrong one for a flight on a FINGER: a drag that takes longer than the
27
+ * animation would have is not stuck, it is being held, and landing it there
28
+ * puts the element back in its screen mid-gesture. So a gesture puts the net
29
+ * away while it drives, and sets it again for the release it hands back.
30
+ */
31
+ suspendBackstop: () => void;
32
+ armBackstop: (seconds: number) => void;
33
+ }
34
+ /**
35
+ * Stage every registered pair as a flight the CALLER drives, and hand back the
36
+ * elements holding it.
37
+ *
38
+ * A programmatic navigation stages its flights when the status flips and lets
39
+ * the compiled hold clock run them. A DRAG has neither: the navigation does not
40
+ * exist yet (it is committed on release, if at all) and there is no hold to
41
+ * mirror. So this takes the same snapshot the status flip would take, stages
42
+ * the same flights under an explicit direction, and leaves them PAUSED at zero
43
+ * for the gesture to move by hand.
44
+ *
45
+ * Exported for `morphSwipe`, which owns the scrubbing; nothing else should
46
+ * stage a flight the runtime does not clock.
47
+ */
48
+ export declare const stageHeldFlights: (store: NavigateStoreApi, status: NavigateStatus) => MorphFlight[];
49
+ /**
50
+ * Forget any delivery the navigation never came to collect. A NEW gesture
51
+ * supersedes the last one; only the gesture's own entry point may do this,
52
+ * because the navigation reaches the scope through `stageHeldFlights` too and
53
+ * clearing there would erase the mark a moment before reading it.
54
+ */
55
+ /**
56
+ * Record that a gesture's release has DELIVERED whatever it is carrying — it
57
+ * plays those flights out to the arrival itself, so the navigation it commits
58
+ * must not stage them again. Whatever is in the air at the release is exactly
59
+ * what the gesture delivers. See `MorphScope.delivered`.
60
+ */
61
+ export declare const clearGestureDeliveries: (store: NavigateStoreApi) => void;
62
+ export declare const markGestureDelivered: (store: NavigateStoreApi) => void;
63
+ /** The flights a scope currently holds — the nested ones included. */
64
+ export declare const heldFlights: (store: NavigateStoreApi) => MorphFlight[];
65
+ export type { MorphFlight };
66
+ /**
67
+ * Register one element as a morph, and return the disposer.
68
+ *
69
+ * Call it before the paint of the frame the element mounts in, and again
70
+ * whenever its screen's status changes — re-registering is cheap and is what
71
+ * lets a screen that was never frozen still take its side of a pop.
72
+ */
73
+ export default function attachMorph(element: HTMLElement, options: AttachMorphOptions): () => void;
@@ -0,0 +1,2 @@
1
+ export declare function preserveDescendantAnimations(root: Element, move: () => void): void;
2
+ export default preserveDescendantAnimations;
@@ -0,0 +1,31 @@
1
+ /** Fraction of the box hidden on each side, as clip-path percentages. */
2
+ export interface MorphClipInset {
3
+ top: number;
4
+ right: number;
5
+ bottom: number;
6
+ left: number;
7
+ }
8
+ /**
9
+ * How much of the element's box its clipping ancestors cut away, per side, as
10
+ * percentages of the box — or null when it is fully visible (within half a
11
+ * pixel) or unmeasurable.
12
+ *
13
+ * Everything is read LIVE, from the element's own bounding rect — never from
14
+ * a rest-space rect computed elsewhere. At staging time the element's screen
15
+ * may already be mid-pose (a cupertino pop reads its revealed screen at
16
+ * translate3d(-30%)), and mixing a rest-space element rect with mid-pose
17
+ * ancestor boxes invents a cut the size of the pose: measured as a
18
+ * destination cell reported 68.74% hidden on its right, which clipped the
19
+ * flight to a sliver. Fractions of a box are invariant under the rigid
20
+ * transforms screens fly by, so live-against-live reads the same answer the
21
+ * rest layout will.
22
+ */
23
+ export declare const visibleInset: (element: Element | null) => MorphClipInset | null;
24
+ /**
25
+ * The clip channel for a flight, or null when neither end was clipped —
26
+ * inset(0) at every frame is not worth an animated property.
27
+ */
28
+ export declare const clipTravel: (from: MorphClipInset | null, to: MorphClipInset | null) => {
29
+ from: MorphClipInset;
30
+ to: MorphClipInset;
31
+ } | null;
@@ -0,0 +1,111 @@
1
+ import { MorphPose, PosePoint } from './morphPose';
2
+ export interface MorphRect {
3
+ x: number;
4
+ y: number;
5
+ width: number;
6
+ height: number;
7
+ }
8
+ export interface MorphSnapshot {
9
+ rect: MorphRect;
10
+ /** The computed `font-size` in px — what makes type grow instead of stretch. */
11
+ fontSize: number | null;
12
+ /**
13
+ * The computed `font-weight`, and the computed `letter-spacing` in px.
14
+ *
15
+ * Size is only one of type's dimensions. A list label at 14px/600 handing
16
+ * over to a heading at 24px/800 that interpolates size alone wears the
17
+ * heading's WEIGHT from the first frame: the type visibly thickens in a
18
+ * single step and then merely gets bigger, which reads as a swap wearing a
19
+ * growth. Tracking is the same story in the other axis.
20
+ *
21
+ * Both are null when the two ends cannot be interpolated — `letter-spacing:
22
+ * normal` is not a length, and an element with no resolved weight has
23
+ * nothing to interpolate from.
24
+ */
25
+ fontWeight: number | null;
26
+ letterSpacing: number | null;
27
+ wordSpacing: number | null;
28
+ lineHeight: number | null;
29
+ /**
30
+ * The computed `aspect-ratio`, or null when the element does not declare one.
31
+ *
32
+ * It is what lets a nested element change SHAPE on the way rather than
33
+ * snapping to its destination's proportions on the first frame: a square
34
+ * thumbnail becoming a 4:3 hero is a ratio interpolating, not a box being
35
+ * replaced.
36
+ */
37
+ aspectRatio: string | null;
38
+ /**
39
+ * The element's own box model at capture: the padding it holds its contents
40
+ * in, and the margin that holds it away from its neighbours.
41
+ *
42
+ * Interpolating the outer box is not enough. The element in flight is the
43
+ * ARRIVAL's tree, so on the first frame it is already wearing the arrival's
44
+ * spacing — a list card with `p-2` handing over to a panel with `p-3` starts
45
+ * with its contents 8px narrower than the ones it is replacing, which is a
46
+ * visible flinch the wrong way at the exact moment of the tap.
47
+ */
48
+ padding: string;
49
+ margin: string;
50
+ /**
51
+ * Everything else the two ends can set differently — the corner, the surface
52
+ * colour, the border, the shadow (see morphPaint's table). Declared as data
53
+ * rather than as a branch per property, because that list was only ever as
54
+ * complete as the last thing someone noticed on glass.
55
+ */
56
+ paint: Record<string, string>;
57
+ }
58
+ export declare const rectCentre: (rect: MorphRect) => PosePoint;
59
+ export declare const captureMorphSnapshot: (element: HTMLElement) => MorphSnapshot;
60
+ /**
61
+ * A painted rect mapped back into the space its ancestor's transform is applied
62
+ * FROM.
63
+ *
64
+ * A screen that is mid-flight (or held at its from-pose) carries a transform,
65
+ * so every rect measured inside it is already displaced. The morph's own
66
+ * transform composes with that displacement rather than replacing it, so the
67
+ * travel has to be computed against the element's undisplaced box — otherwise
68
+ * every push under a sliding transition would start the element a screen-width
69
+ * away from where the eye last saw it.
70
+ */
71
+ export declare const untransformRect: (painted: MorphRect, ancestor: MorphPose, ancestorCentre: PosePoint) => MorphRect;
72
+ /**
73
+ * The transform an element is ACTUALLY wearing right now, read off its computed
74
+ * matrix rather than inferred from the variant it is supposed to be playing.
75
+ *
76
+ * Inferring it was a bug with a name: a held screen usually sits at its
77
+ * from-pose, but the destination PARK rules put it at its DESTINATION instead
78
+ * (so the browser rasterises the tiles the animation is about to reveal), and a
79
+ * measurement corrected for a displacement the screen was not wearing lands a
80
+ * screen-height away from where anything is. The matrix is true in every one of
81
+ * those states — parked, held, mid-flight, at rest.
82
+ *
83
+ * Rotation and skew are not represented: nothing in the library rotates a
84
+ * screen, and a rect is not a rotated shape anyway.
85
+ */
86
+ export declare const readElementPose: (element: HTMLElement) => MorphPose;
87
+ /**
88
+ * The centre an ancestor's transform is applied about, recovered from its
89
+ * painted rect. Scale leaves the centre where it is, so the translation is the
90
+ * whole difference — which is why this needs no scale term.
91
+ */
92
+ export declare const untransformedCentre: (painted: MorphRect, ancestor: MorphPose) => PosePoint;
93
+ /**
94
+ * The pose that puts `element` exactly where `target` is — the F of FLIP.
95
+ *
96
+ * Both rects live in the same (untransformed) space, and the transform is
97
+ * applied about the element's own centre, so the translation is centre-to-
98
+ * centre and the scale is the size ratio. Returns the identity when either box
99
+ * has no area: an unlaid-out element has no honest travel to compute, and
100
+ * dividing by its zero would produce an infinity that reaches the compositor.
101
+ */
102
+ /**
103
+ * The transform that maps one box onto another, about the element's own centre.
104
+ *
105
+ * Only the GHOST uses it. Everything real animates its LAYOUT box so its
106
+ * contents lay themselves out at every size; a copy that is on its way out must
107
+ * do the opposite — keep the layout it was captured with and simply follow,
108
+ * or it re-wraps its own text while the real element re-wraps differently and
109
+ * the two print over each other.
110
+ */
111
+ export declare const followPose: (target: MorphRect, element: MorphRect) => MorphPose;
@@ -0,0 +1,190 @@
1
+ import { AnimationOptions, TransitionTarget } from '../transition/cssTypes';
2
+ import { MorphPose } from './morphPose';
3
+ import { MorphClipInset } from './morphClip';
4
+ import { MorphRect } from './morphGeometry';
5
+ /** The non-transform half of an authored target — everything the geometry keyframe must not carry. */
6
+ export declare const contentDecls: (target: TransitionTarget | undefined | null) => import('../transition/compileTransitionStyles').CssDecl[];
7
+ export interface MorphTravel {
8
+ /** Where the element starts, relative to where it belongs. */
9
+ from: MorphPose;
10
+ /**
11
+ * Where it ends. The identity for anything that belongs at its own layout —
12
+ * which is everything except a GHOST, whose own box is the departure's and
13
+ * which therefore has to travel TO the arrival's instead.
14
+ */
15
+ to?: MorphPose;
16
+ /** An author's transform flourish, layered on top of the travel. */
17
+ authoredFrom: MorphPose;
18
+ authoredTo: MorphPose;
19
+ duration: number;
20
+ /** Seconds from the release, platform head included. */
21
+ start: number;
22
+ ease: AnimationOptions["ease"];
23
+ }
24
+ export interface MorphKeyframeSet {
25
+ /** `@keyframes` blocks to insert, in order. */
26
+ rules: string[];
27
+ /** The `animation` shorthand to put on the element. */
28
+ animation: string;
29
+ /**
30
+ * The animation whose end LANDS the flight — the geometry one where there is
31
+ * one, the corner where the corner is all that changes.
32
+ */
33
+ geometryName: string;
34
+ }
35
+ /**
36
+ * The keyframes and the `animation` shorthand for one side of a morph.
37
+ *
38
+ * Three animations, never one: the geometry keyframe carries `transform` and
39
+ * NOTHING else, because a keyframe listing a property the compositor cannot
40
+ * animate drops that whole animation to the main thread — and the travel is the
41
+ * one that must never leave it. The cross-fade and the corner ride alongside on
42
+ * their own clocks, which is also what lets them have their own windows: the
43
+ * fade has to be over while the two sides are still on top of each other, the
44
+ * corner has to track the scale for the whole flight.
45
+ *
46
+ * Two endpoints and the authored easing, because the element is staged in the
47
+ * FLIGHT LAYER: it is not inside a screen any more, so there is no screen
48
+ * motion left to compose with and nothing to sample.
49
+ */
50
+ export declare const buildMorphKeyframes: (input: {
51
+ id: string;
52
+ travel: MorphTravel;
53
+ /**
54
+ * The element's LAYOUT BOX at each end, when it is the thing being animated.
55
+ *
56
+ * A box, not a scale. `transform: scale` stretches everything inside — text
57
+ * becomes a blown-up bitmap and the contents cannot find their own places —
58
+ * whereas animating the box lets the subtree lay itself out at every size on
59
+ * the way, which is what "it grows" is supposed to mean. It costs layout per
60
+ * frame on one subtree, which is the honest price of the thing actually
61
+ * being laid out.
62
+ */
63
+ box?: {
64
+ from: MorphRect;
65
+ to: MorphRect;
66
+ } | null;
67
+ /** Type morphs by growing, not by being scaled: px at each end. */
68
+ fontSize?: {
69
+ from: number;
70
+ to: number;
71
+ } | null;
72
+ /** Type's other two dimensions, so it re-typesets rather than merely re-sizing. */
73
+ fontWeight?: {
74
+ from: number;
75
+ to: number;
76
+ } | null;
77
+ letterSpacing?: {
78
+ from: number;
79
+ to: number;
80
+ } | null;
81
+ wordSpacing?: {
82
+ from: number;
83
+ to: number;
84
+ } | null;
85
+ lineHeight?: {
86
+ from: number;
87
+ to: number;
88
+ } | null;
89
+ /** A nested element changes SHAPE by interpolating its ratio, not by snapping to it. */
90
+ aspectRatio?: {
91
+ from: string;
92
+ to: string;
93
+ } | null;
94
+ /** The spacing the two ends hold their contents at, and stand apart by. */
95
+ padding?: {
96
+ from: string;
97
+ to: string;
98
+ } | null;
99
+ margin?: {
100
+ from: string;
101
+ to: string;
102
+ } | null;
103
+ /**
104
+ * A nested element's OWN box, width and height only, for the one geometry
105
+ * the container cannot carry for it. Riding assumes the container's width
106
+ * interpolation sizes the child, and it does when the container GROWS in
107
+ * width; a container that starts at full width (a list row becoming a page)
108
+ * lays the arrival out at destination width from the first frame, and a
109
+ * thumbnail inside it lands full-size instantly instead of growing. Measured
110
+ * on the playground's list: a 48px thumb rendered as a full-width strip on
111
+ * frame one. From-size to staged-size, exact at both ends.
112
+ */
113
+ size?: {
114
+ from: {
115
+ width: number;
116
+ height: number;
117
+ };
118
+ to: {
119
+ width: number;
120
+ height: number;
121
+ };
122
+ } | null;
123
+ /**
124
+ * What the scrollport was hiding at each end, as inset percentages — so a
125
+ * cell clipped at the list's edge slides out from under the chrome covering
126
+ * it instead of materialising whole over it (see morphClip). Percentages,
127
+ * because the box is itself animating and the visible FRACTION is the thing
128
+ * to preserve.
129
+ */
130
+ clip?: {
131
+ from: MorphClipInset;
132
+ to: MorphClipInset;
133
+ } | null;
134
+ fade: {
135
+ from: TransitionTarget | null;
136
+ to: TransitionTarget | null;
137
+ duration: number;
138
+ /** Seconds to hold the from-pose before the fade runs, on top of `travel.start`. */
139
+ delay?: number;
140
+ } | null;
141
+ /**
142
+ * Everything the two ends paint differently — corner, surface, border,
143
+ * shadow. One animation, so the travel keyframe stays on the compositor.
144
+ */
145
+ paint: {
146
+ property: string;
147
+ from: string;
148
+ to: string;
149
+ }[];
150
+ }) => MorphKeyframeSet;
151
+ /**
152
+ * The CAMERA: the transform that takes a screen from resting to "zoomed onto
153
+ * this element", for a flight that carries its screen.
154
+ *
155
+ * One uniform scale and one translate, both literal — the same discipline the
156
+ * travel keeps, and for the same reason: a compiled animation whose values come
157
+ * from custom properties was device-bisected off the compositor on WebKit
158
+ * (see the literal-timing note in compileTransitionStyles).
159
+ *
160
+ * The scale comes from WIDTH alone. The element's own box changes aspect across
161
+ * the flight, so no single uniform scale can match both axes, and width is the
162
+ * axis a column grid is built on: at the end of the zoom the tapped cell is
163
+ * exactly as wide as the screen, which is what puts everything else off the
164
+ * edges.
165
+ *
166
+ * The animation is emitted as LONGHANDS, never the `animation` shorthand: the
167
+ * shorthand would also write `animation-play-state`, and that longhand belongs
168
+ * to the compiled hold — the camera has to pause and release with its screen
169
+ * like everything else in the flight.
170
+ */
171
+ export declare const buildCameraKeyframes: (input: {
172
+ id: string;
173
+ /** The screen's transform-origin, in the same space as the rects. */
174
+ origin: {
175
+ x: number;
176
+ y: number;
177
+ };
178
+ /** The element's box on the screen being carried, and at the other end. */
179
+ small: MorphRect;
180
+ big: MorphRect;
181
+ /** True when the screen is arriving (a pop): it starts zoomed and settles. */
182
+ settling: boolean;
183
+ duration: number;
184
+ start: number;
185
+ ease: AnimationOptions["ease"];
186
+ selector: string;
187
+ }) => {
188
+ rules: string[];
189
+ name: string;
190
+ };
@@ -0,0 +1,14 @@
1
+ import { NavigateStoreApi } from '../navigate/store';
2
+ /**
3
+ * Publish the element a scope's flights should be staged in. A binding calls
4
+ * this from its Router lifecycle — the Router is the only thing that knows
5
+ * which box bounds its screens.
6
+ */
7
+ export declare const registerMorphLayer: (store: NavigateStoreApi, element: HTMLElement | null) => void;
8
+ /**
9
+ * The layer to stage a flight in, creating a document-level fallback for a
10
+ * binding that publishes none. The fallback is correct for a root Router (its
11
+ * screens fill the viewport anyway) and wrong only for a CONTAINED one, which
12
+ * is exactly the case a binding is expected to publish.
13
+ */
14
+ export declare const resolveMorphLayer: (store: NavigateStoreApi) => HTMLElement | null;
@@ -0,0 +1,31 @@
1
+ export interface PaintChannel {
2
+ /** The property as it is written in a keyframe. */
3
+ property: string;
4
+ /**
5
+ * Read as four sides rather than one value. A shorthand's computed value is
6
+ * empty when the sides disagree, which is exactly the case worth carrying.
7
+ */
8
+ sides?: readonly [string, string, string, string];
9
+ /**
10
+ * Rewrite a captured value into an interpolable one. A keyword end turns the
11
+ * whole channel into a discrete swap at the eased midpoint — worse than not
12
+ * carrying it, because it fires mid-flight where nothing else steps.
13
+ */
14
+ normalize?: (value: string) => string;
15
+ }
16
+ export declare const PAINT_CHANNELS: readonly PaintChannel[];
17
+ type Styles = Record<string, string | undefined> | null | undefined;
18
+ /** Both ends' values for every channel, keyed by the property a keyframe wants. */
19
+ export declare const capturePaint: (styles: Styles) => Record<string, string>;
20
+ /**
21
+ * The channels worth animating: present at both ends and different.
22
+ *
23
+ * `exclude` is how a morph transition opts out of one — the built-in `text`
24
+ * preset turns the corner off, because type has none worth moving.
25
+ */
26
+ export declare const paintTravel: (from: Record<string, string>, to: Record<string, string>, exclude?: ReadonlySet<string>) => {
27
+ property: string;
28
+ from: string;
29
+ to: string;
30
+ }[];
31
+ export {};
@@ -0,0 +1,44 @@
1
+ import { TransitionTarget } from '../transition/cssTypes';
2
+ export interface MorphPose {
3
+ /** Translation in px. */
4
+ x: number;
5
+ y: number;
6
+ scaleX: number;
7
+ scaleY: number;
8
+ /** Degrees. */
9
+ rotate: number;
10
+ }
11
+ export interface PoseBox {
12
+ width: number;
13
+ height: number;
14
+ }
15
+ export interface PosePoint {
16
+ x: number;
17
+ y: number;
18
+ }
19
+ export declare const IDENTITY_POSE: MorphPose;
20
+ export declare const resolveLength: (raw: string | number | undefined, basis: number) => number | null;
21
+ /**
22
+ * The transform channels of an authored target as numbers, or `null` when one
23
+ * of them is a length this module cannot resolve (see resolveLength).
24
+ */
25
+ export declare const resolvePose: (target: TransitionTarget | undefined | null, box: PoseBox) => MorphPose | null;
26
+ /** Whether an authored target moves anything this module represents. */
27
+ export declare const poseIsIdentity: (pose: MorphPose) => boolean;
28
+ /**
29
+ * One pose as a CSS transform value. `translate3d` rather than translateX/Y for
30
+ * the same reason the keyframes compiler uses it: Chromium pixel-snaps a
31
+ * 2D-transform-animated layer on raster-heavy content, and the 3D form keeps
32
+ * the layer on the texture-filtered path that slides sub-pixel smoothly.
33
+ */
34
+ export declare const poseToCss: (pose: MorphPose) => string;
35
+ /**
36
+ * Several poses as ONE transform value, outermost first.
37
+ *
38
+ * Concatenation IS composition in CSS — `transform: A B` maps a point through B
39
+ * and then A — so the runtime never multiplies matrices. That is what lets the
40
+ * measured travel and an author's flourish stack on one element instead of
41
+ * needing a wrapper each.
42
+ */
43
+ export declare const composePosesToCss: (poses: MorphPose[]) => string;
44
+ export declare const interpolatePose: (from: MorphPose, to: MorphPose, progress: number) => MorphPose;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Insert one flight's rules and return the disposer that removes exactly them.
3
+ *
4
+ * The rules are tracked by identity, not by index: a concurrent flight (two
5
+ * morphing elements in one navigation, or a second navigation interrupting the
6
+ * first) inserts and drops rules in between, and an index captured at insertion
7
+ * would by then point at someone else's keyframes.
8
+ */
9
+ export declare const insertMorphRules: (rules: string[]) => (() => void);
@@ -0,0 +1,43 @@
1
+ import { NavigateStatus } from '../navigate/store';
2
+ import { AnimationOptions } from '../transition/cssTypes';
3
+ import { TransitionVariant } from '../transition/typing';
4
+ import { MorphRect } from './morphGeometry';
5
+ export declare const headSeconds: (status: NavigateStatus) => number;
6
+ export interface MorphSide {
7
+ /**
8
+ * Where the element's box belongs AT REST, in viewport coordinates.
9
+ *
10
+ * Not simply its measured rect: a screen mid-flight (or held at its from-pose)
11
+ * carries a transform, and every rect measured inside it is displaced by it.
12
+ * The travel has to be computed against the undisplaced box, or a push under a
13
+ * sliding transition would aim a screen-width away from where the element ends.
14
+ */
15
+ rect: MorphRect;
16
+ fontSize: number | null;
17
+ fontWeight: number | null;
18
+ letterSpacing: number | null;
19
+ wordSpacing: number | null;
20
+ lineHeight: number | null;
21
+ aspectRatio: string | null;
22
+ padding: string;
23
+ margin: string;
24
+ paint: Record<string, string>;
25
+ /**
26
+ * Whether this screen's transition MOVES it — read from the DEFINITION, not
27
+ * from the element: at the moment a flight is staged the arriving screen is
28
+ * parked at its DESTINATION with no transform on it yet (`park-under`), so
29
+ * asking the DOM answers no for every screen that is about to slide in.
30
+ */
31
+ screenMoves: boolean;
32
+ /** The screen's own timing, so a morph that authors none lands with its screen. */
33
+ screenDuration: number;
34
+ screenEase: AnimationOptions["ease"];
35
+ }
36
+ /**
37
+ * Where one side of a morph really is, and how long its screen takes.
38
+ *
39
+ * The screen is read from the DOM PROTOCOL — its transition name is an
40
+ * attribute — rather than from a store, so a morph works the same for any
41
+ * binding and needs nothing threaded through from the consumer's tree.
42
+ */
43
+ export declare const resolveMorphSide: (element: HTMLElement, screen: HTMLElement, variant: TransitionVariant) => MorphSide;
@@ -0,0 +1,24 @@
1
+ import { NavigateStatus, NavigateStoreApi } from '../navigate/store';
2
+ export interface MorphSwipe {
3
+ /** Move every staged flight to this fraction of its travel (0 → 1). */
4
+ scrub: (progress: number) => void;
5
+ /**
6
+ * Hand the flights back to the browser.
7
+ *
8
+ * `commit` plays them out to the arrival — the gesture became a navigation.
9
+ * Otherwise they run BACKWARDS to where they started and the elements go
10
+ * home, which is the only way back: a flight that is merely stopped leaves
11
+ * the element in the layer, outside the tree its consumer wrote.
12
+ */
13
+ settle: (commit: boolean, seconds: number) => void;
14
+ /** Whether anything is actually flying (a screen pair with no shared element is not). */
15
+ readonly active: boolean;
16
+ }
17
+ /**
18
+ * Stage the flights for a gesture and return the handle that drives them.
19
+ *
20
+ * `status` is the direction the gesture WOULD commit — `"POPPING"` for a
21
+ * back-swipe — because the pairing reads it to decide which side is arriving.
22
+ */
23
+ export declare const beginMorphSwipe: (store: NavigateStoreApi, status?: NavigateStatus) => MorphSwipe;
24
+ export default beginMorphSwipe;
@@ -8,7 +8,6 @@ export interface DistanceOptions {
8
8
  until?: string;
9
9
  }
10
10
  export interface NavigateOptions extends DistanceOptions {
11
- layoutId?: string | number;
12
11
  transitionName?: TransitionName;
13
12
  }
14
13
  export interface PopOptions extends DistanceOptions {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export default function publishRideBox(element: HTMLElement): () => void;
@@ -1,5 +1,6 @@
1
1
  declare module '../typing' {
2
2
  interface RegisterTransition {
3
+ "custom-snap-percent": "custom-snap-percent";
3
4
  "custom-fade-blur": "custom-fade-blur";
4
5
  "custom-slide-fade": "custom-slide-fade";
5
6
  "custom-rich-css": "custom-rich-css";
@@ -13,6 +14,7 @@ declare module '../decorator/typing' {
13
14
  interface RegisterDecorator {
14
15
  "rich-deco": "rich-deco";
15
16
  "held-deco": "held-deco";
17
+ "moving-deco": "moving-deco";
16
18
  "authored-deco": "authored-deco";
17
19
  }
18
20
  }
@@ -0,0 +1 @@
1
+ export {};