@flemo/core 1.29.0 → 2.0.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.
- package/dist/core/TaskManger.d.ts +13 -0
- package/dist/core/engine/__tests__/architectureDoc.test.d.ts +10 -0
- package/dist/core/engine/__tests__/diagnosticRegistry.test.d.ts +10 -0
- package/dist/core/engine/__tests__/flightRouting.test.d.ts +1 -0
- package/dist/core/engine/__tests__/landingGovernor.test.d.ts +1 -0
- package/dist/core/engine/__tests__/layerRiders.test.d.ts +1 -0
- package/dist/core/engine/__tests__/participantLayers.test.d.ts +1 -0
- package/dist/core/engine/__tests__/singleResolution.test.d.ts +1 -0
- package/dist/core/engine/arrivalHold.d.ts +1 -1
- package/dist/core/engine/cancelResume.d.ts +17 -0
- package/dist/core/engine/compositorWarmUp.d.ts +1 -1
- package/dist/core/engine/createSwipeController.d.ts +16 -0
- package/dist/core/engine/createTransitionEngine.d.ts +2 -1
- package/dist/core/engine/diagnosticFlags.d.ts +2 -10
- package/dist/core/engine/diagnosticRegistry.d.ts +38 -0
- package/dist/core/engine/flightHolds.d.ts +22 -0
- package/dist/core/engine/flightParticipants.d.ts +8 -0
- package/dist/core/engine/flightRouting.d.ts +91 -0
- package/dist/core/engine/gpuPipelinePrewarm.d.ts +1 -1
- package/dist/core/engine/imageDecodeOffloader.d.ts +1 -1
- package/dist/core/engine/landingGovernor.d.ts +3 -0
- package/dist/core/engine/layerRiders.d.ts +21 -0
- package/dist/core/engine/participantLayers.d.ts +12 -0
- package/dist/core/engine/types.d.ts +2 -1
- package/dist/dom/__tests__/attributes.test.d.ts +10 -0
- package/dist/dom/__tests__/stacking.test.d.ts +1 -0
- package/dist/dom/attributes.d.ts +239 -0
- package/dist/dom/stacking.d.ts +28 -0
- package/dist/history/store.d.ts +0 -1
- package/dist/index.d.ts +20 -4
- package/dist/index.mjs +2880 -1807
- package/dist/morph/__tests__/attachMorph.test.d.ts +1 -0
- package/dist/morph/__tests__/morphAnimations.test.d.ts +1 -0
- package/dist/morph/__tests__/morphClip.test.d.ts +1 -0
- package/dist/morph/__tests__/morphGeometry.test.d.ts +1 -0
- package/dist/morph/__tests__/morphKeyframes.test.d.ts +1 -0
- package/dist/morph/__tests__/morphLayer.test.d.ts +1 -0
- package/dist/morph/__tests__/morphPaint.test.d.ts +1 -0
- package/dist/morph/__tests__/morphPose.test.d.ts +1 -0
- package/dist/morph/__tests__/morphSheet.test.d.ts +1 -0
- package/dist/morph/__tests__/morphSide.test.d.ts +1 -0
- package/dist/morph/__tests__/morphSwipe.test.d.ts +1 -0
- package/dist/morph/attachMorph.d.ts +59 -0
- package/dist/morph/morphAnimations.d.ts +2 -0
- package/dist/morph/morphClip.d.ts +31 -0
- package/dist/morph/morphGeometry.d.ts +111 -0
- package/dist/morph/morphKeyframes.d.ts +190 -0
- package/dist/morph/morphLayer.d.ts +14 -0
- package/dist/morph/morphPaint.d.ts +31 -0
- package/dist/morph/morphPose.d.ts +44 -0
- package/dist/morph/morphSheet.d.ts +9 -0
- package/dist/morph/morphSide.d.ts +43 -0
- package/dist/morph/morphSwipe.d.ts +24 -0
- package/dist/navigate/createNavigationController.d.ts +0 -1
- package/dist/navigate/store.d.ts +1 -0
- package/dist/platform/__tests__/displayCadence.test.d.ts +1 -0
- package/dist/platform/__tests__/displayProbe.test.d.ts +1 -0
- package/dist/platform/__tests__/engineProbes.test.d.ts +1 -0
- package/dist/platform/__tests__/legacyBlinkGate.test.d.ts +1 -0
- package/dist/platform/__tests__/profile.test.d.ts +1 -0
- package/dist/platform/__tests__/steadySixtyCadence.test.d.ts +1 -0
- package/dist/platform/displayCadence.d.ts +3 -0
- package/dist/platform/displayProbe.d.ts +5 -0
- package/dist/platform/engineProbes.d.ts +4 -0
- package/dist/platform/profile.d.ts +70 -0
- package/dist/{core/engine → platform}/steadySixtyCadence.d.ts +1 -1
- package/dist/runtime/__tests__/flemoRuntime.test.d.ts +1 -0
- package/dist/runtime/flemoRuntime.d.ts +9 -0
- package/dist/transition/compileTransitionStyles.d.ts +0 -1
- package/dist/transition/cubicBezier.d.ts +25 -0
- package/dist/transition/morphTransition/__tests__/createMorphTransition.test.d.ts +1 -0
- package/dist/transition/morphTransition/createMorphTransition.d.ts +13 -0
- package/dist/transition/morphTransition/createRawMorphTransition.d.ts +17 -0
- package/dist/transition/morphTransition/morphTransition.d.ts +2 -0
- package/dist/transition/morphTransition/shared.d.ts +2 -0
- package/dist/transition/morphTransition/text.d.ts +2 -0
- package/dist/transition/morphTransition/typing.d.ts +72 -0
- package/dist/transition/morphTransition/zoom.d.ts +2 -0
- package/dist/transition/registerTransitionDefinitions.d.ts +2 -1
- package/dist/transition/swipeSettle.d.ts +82 -1
- package/dist/transition/typing.d.ts +2 -2
- package/package.json +7 -7
- package/dist/core/engine/driverPolicy.d.ts +0 -12
- package/dist/core/engine/landingPixelSnap.d.ts +0 -10
- package/dist/core/engine/motionDriverKind.d.ts +0 -7
- package/dist/core/engine/transitionPlayer.d.ts +0 -40
- /package/dist/core/engine/__tests__/{driverPolicy.test.d.ts → createSwipeController.dragHooks.test.d.ts} +0 -0
- /package/dist/core/engine/__tests__/{landingPixelSnap.test.d.ts → createSwipeController.layerRelease.test.d.ts} +0 -0
- /package/dist/core/engine/__tests__/{motionDriverKind.test.d.ts → createSwipeController.stuckGesture.test.d.ts} +0 -0
- /package/dist/core/engine/__tests__/{steadySixtyCadence.test.d.ts → createSwipeController.velocity.test.d.ts} +0 -0
- /package/dist/core/engine/__tests__/{transitionPlayer.test.d.ts → flightParticipants.test.d.ts} +0 -0
- /package/dist/{core/engine → platform}/governedCompiled.d.ts +0 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export interface PlatformProfile {
|
|
2
|
+
/**
|
|
3
|
+
* This engine presents its compiled screen animations FROM THE MAIN THREAD
|
|
4
|
+
* (WebKit) rather than off the compositor (Blink). Everything about
|
|
5
|
+
* protecting a flight's opening follows from this one fact: where the clock
|
|
6
|
+
* is stamped on the main thread, a heavy commit between the stamp and the
|
|
7
|
+
* first paint is aged away rather than ridden through.
|
|
8
|
+
*/
|
|
9
|
+
readonly mainThreadPresented: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Flip the hold attribute straight onto the DOM inside the readiness rAF
|
|
12
|
+
* instead of routing the release through a state commit. A rAF callback and
|
|
13
|
+
* its own frame's rendering update are atomic, so clock-start and first paint
|
|
14
|
+
* become simultaneous by construction.
|
|
15
|
+
*
|
|
16
|
+
* Device-verified on three populations; see readDesktopReleaseFlipFlag. An
|
|
17
|
+
* authored `driver: "native"` transition takes it too — pass
|
|
18
|
+
* `authoredNativeDriver` to fold that in.
|
|
19
|
+
*/
|
|
20
|
+
readonly atomicReleaseFlip: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Hand the release's reconcile to the NEXT frame rather than flushing it
|
|
23
|
+
* synchronously, so it stops competing with the flight's first present.
|
|
24
|
+
* Only meaningful where the flip already released the hold — without the
|
|
25
|
+
* flip, the state commit IS the release.
|
|
26
|
+
*/
|
|
27
|
+
readonly deferReleaseCommit: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Hold the release until the entering screen's mount render quiesces, so a
|
|
30
|
+
* heavy screen's own commit storm cannot eat the opening frames.
|
|
31
|
+
*/
|
|
32
|
+
readonly renderSettleGate: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Park a push's entering screen ON TOP at near-zero opacity (so the browser
|
|
35
|
+
* genuinely paints its tiles during the hold) rather than beneath its cover.
|
|
36
|
+
*/
|
|
37
|
+
readonly parkOver: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Keep the screen scope's layer promoted at REST. Off everywhere by default:
|
|
40
|
+
* a promotion is also a stacking context, and at rest it outranks any
|
|
41
|
+
* consumer overlay inside the screen.
|
|
42
|
+
*/
|
|
43
|
+
readonly restLayerPromotion: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Rewrite oversized `<img>` sources to decoded-to-scale blobs off the main
|
|
46
|
+
* thread. Auto on legacy Android Blink only — it touches consumer content,
|
|
47
|
+
* so it must never run where the paint is already cheap.
|
|
48
|
+
*/
|
|
49
|
+
readonly imageDecodeOffload: boolean;
|
|
50
|
+
}
|
|
51
|
+
export interface PlatformProfileInput {
|
|
52
|
+
/**
|
|
53
|
+
* The transition being flown authored `driver: "native"` — an explicit opt-in
|
|
54
|
+
* to clock surgery, which carries the atomic release flip with it. The
|
|
55
|
+
* binding knows this and core does not, so it is the one input the profile
|
|
56
|
+
* takes.
|
|
57
|
+
*/
|
|
58
|
+
readonly authoredNativeDriver?: boolean;
|
|
59
|
+
}
|
|
60
|
+
export declare const resolvePlatformProfile: (input?: PlatformProfileInput) => PlatformProfile;
|
|
61
|
+
/**
|
|
62
|
+
* The REST-promotion decision on its own, as a module-stable function.
|
|
63
|
+
*
|
|
64
|
+
* A binding that server-renders must read this through a hydration-scoped
|
|
65
|
+
* snapshot (it reaches the DOM as an inline style, so a render-phase read
|
|
66
|
+
* mismatches the server HTML), and React's `useSyncExternalStore` requires the
|
|
67
|
+
* reader identity to be stable across renders — which an inline
|
|
68
|
+
* `() => resolvePlatformProfile().restLayerPromotion` would not be.
|
|
69
|
+
*/
|
|
70
|
+
export declare const restLayerPromotionEnabled: () => boolean;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const HIGH_REFRESH_MAX_INTERVAL_MS = 12;
|
|
2
2
|
export declare const reportInFlightCadence: (rawMedianMs: number, rawMaxMs?: number) => void;
|
|
3
3
|
export declare const steadySixtyVerified: () => boolean;
|
|
4
|
-
export declare const
|
|
4
|
+
export declare const steadySixtyDesktopProfile: () => boolean;
|
|
5
5
|
export declare const resetSteadySixtyForTests: () => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Start flemo's ambient machinery, and return the release for this holder.
|
|
3
|
+
*
|
|
4
|
+
* A binding calls this once per Router mount and releases on unmount. Repeat
|
|
5
|
+
* calls share one runtime; the last release tears it down. Safe on the server:
|
|
6
|
+
* every piece degrades to a no-op without a document.
|
|
7
|
+
*/
|
|
8
|
+
export declare const startFlemoRuntime: () => (() => void);
|
|
9
|
+
export declare const resetFlemoRuntimeForTests: () => void;
|
|
@@ -9,7 +9,6 @@ export type CssDecl = {
|
|
|
9
9
|
export declare const collectAnimatedProperties: (transition: Pick<Transition, "initial" | "variants">) => string[];
|
|
10
10
|
export declare const targetToDecls: (target: TransitionVariantValue["value"] | InitialTarget) => CssDecl[];
|
|
11
11
|
export declare const easingToCss: (ease: AnimationOptions["ease"] | undefined) => string;
|
|
12
|
-
export declare const softenFrontLoadedEasing: (easingCss: string, durationS: number) => string | null;
|
|
13
12
|
export declare const animationName: (scope: "screen" | "decorator" | "part", name: string, variant: TransitionVariant) => string;
|
|
14
13
|
export declare const HEAD_ANIMATION_SUFFIXES: readonly ["-gov", "-deskhead", "-govcreep"];
|
|
15
14
|
export declare const matchesFlightAnimationName: (eventName: string, expectedName: string) => boolean;
|
|
@@ -1,4 +1,29 @@
|
|
|
1
1
|
import { AnimationOptions } from './cssTypes';
|
|
2
2
|
export type EasingFunction = (progress: number) => number;
|
|
3
3
|
export declare const cubicBezier: (x1: number, y1: number, x2: number, y2: number) => EasingFunction;
|
|
4
|
+
/**
|
|
5
|
+
* The INVERSE of a CSS timing function: given the value progress you want to
|
|
6
|
+
* see, the time progress that produces it.
|
|
7
|
+
*
|
|
8
|
+
* A scrubbed animation needs this. Setting an animation's clock to the drag's
|
|
9
|
+
* fraction moves the CLOCK linearly, and what the eye follows is the curve's
|
|
10
|
+
* output — with an ease that opens slowly, a finger a tenth of the way across
|
|
11
|
+
* moves the element a fiftieth, and everything it did not do is left for the
|
|
12
|
+
* release to rush through. Inverting the curve makes the element track the
|
|
13
|
+
* finger and leaves the release only what is really left.
|
|
14
|
+
*
|
|
15
|
+
* Binary search on y, the same shape as `cubicBezier`'s search on x. An
|
|
16
|
+
* overshooting curve (`backOut`, `anticipate`) is not monotonic in y, so the
|
|
17
|
+
* search returns the first crossing — which is the one before the overshoot,
|
|
18
|
+
* and the only one a drag can mean.
|
|
19
|
+
*/
|
|
20
|
+
export declare const invertEasing: (ease: AnimationOptions["ease"] | undefined) => EasingFunction;
|
|
21
|
+
/**
|
|
22
|
+
* The control points behind an authored ease, named or spelled out — `null`
|
|
23
|
+
* for `linear`, which has no handles to work with.
|
|
24
|
+
*
|
|
25
|
+
* Exported for the swipe release, which re-aims an authored curve's opening
|
|
26
|
+
* slope onto the gesture that produced it (see swipeSettle.ts).
|
|
27
|
+
*/
|
|
28
|
+
export declare const easeControlPoints: (ease: AnimationOptions["ease"] | undefined) => [number, number, number, number] | null;
|
|
4
29
|
export declare const resolveEasing: (ease: AnimationOptions["ease"] | undefined) => EasingFunction;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { InitialTarget } from '../cssTypes';
|
|
2
|
+
import { TransitionVariantValue } from '../typing';
|
|
3
|
+
import { MorphTransition, MorphTransitionName, MorphTransitionOptions } from './typing';
|
|
4
|
+
interface CreateMorphProps {
|
|
5
|
+
name: MorphTransitionName;
|
|
6
|
+
initial: InitialTarget;
|
|
7
|
+
idle: TransitionVariantValue;
|
|
8
|
+
enter: TransitionVariantValue;
|
|
9
|
+
exit: TransitionVariantValue;
|
|
10
|
+
options?: MorphTransitionOptions;
|
|
11
|
+
}
|
|
12
|
+
export default function createMorphTransition({ name, initial, idle, enter, exit, options }: CreateMorphProps): MorphTransition;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { InitialTarget } from '../cssTypes';
|
|
2
|
+
import { TransitionVariantValue } from '../typing';
|
|
3
|
+
import { MorphTransition, MorphTransitionName, MorphTransitionOptions } from './typing';
|
|
4
|
+
interface CreateRawMorphProps {
|
|
5
|
+
name: MorphTransitionName;
|
|
6
|
+
initial: InitialTarget;
|
|
7
|
+
idle: TransitionVariantValue;
|
|
8
|
+
pushOnEnter: TransitionVariantValue;
|
|
9
|
+
pushOnExit: TransitionVariantValue;
|
|
10
|
+
replaceOnEnter: TransitionVariantValue;
|
|
11
|
+
replaceOnExit: TransitionVariantValue;
|
|
12
|
+
popOnEnter: TransitionVariantValue;
|
|
13
|
+
popOnExit: TransitionVariantValue;
|
|
14
|
+
options?: MorphTransitionOptions;
|
|
15
|
+
}
|
|
16
|
+
export default function createRawMorphTransition({ name, initial, idle, pushOnEnter, pushOnExit, replaceOnEnter, replaceOnExit, popOnEnter, popOnExit, options }: CreateRawMorphProps): MorphTransition;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { BaseTransition, TransitionVariant } from '../typing';
|
|
2
|
+
export interface RegisterMorphTransition {
|
|
3
|
+
}
|
|
4
|
+
export type MorphTransitionName = RegisterMorphTransition[keyof RegisterMorphTransition] | "shared" | "text" | "zoom" | (string & {});
|
|
5
|
+
/** The preset every morph falls back to when no name is given. */
|
|
6
|
+
export declare const DEFAULT_MORPH_TRANSITION_NAME = "shared";
|
|
7
|
+
export type MorphTransitionOptions = {
|
|
8
|
+
/**
|
|
9
|
+
* The share of the flight over which the GHOST dissolves — the copy of the
|
|
10
|
+
* element being replaced that the runtime carries inside the flight (0–1,
|
|
11
|
+
* default 0.55).
|
|
12
|
+
*
|
|
13
|
+
* It is what makes a travel show the right thing at both ends: the flight
|
|
14
|
+
* begins as an exact copy of what was on glass and dissolves into the real
|
|
15
|
+
* arriving element while the box moves. Set it to 0 to carry no copy, which
|
|
16
|
+
* cuts straight to the arrival's content on the first frame.
|
|
17
|
+
*
|
|
18
|
+
* The arriving element stays opaque underneath throughout. Fading both would
|
|
19
|
+
* bleed the background through the pair by a(1 - a) — a luminance dip
|
|
20
|
+
* peaking at 25% in the middle of the hand-over.
|
|
21
|
+
*
|
|
22
|
+
* THE WINDOW IS WHAT THE DEPARTURE'S OWN CONTENT LEAVES OVER. This used to be
|
|
23
|
+
* 0.22 — three frames of a short flight — on the reasoning that holding the
|
|
24
|
+
* copy longer let the two layouts drift apart underneath it and print as
|
|
25
|
+
* doubled text. That reasoning was written when the copy painted everything,
|
|
26
|
+
* including the paired elements. It does not now: a paired descendant is
|
|
27
|
+
* already invisible in the copy (the real one is morphing underneath it), so
|
|
28
|
+
* all the copy is holding is content with NO counterpart — a caption, a body
|
|
29
|
+
* paragraph, a button that exists on one side only. Three frames is not that
|
|
30
|
+
* content leaving; it is that content being cut, which is exactly what a pop
|
|
31
|
+
* looked like next to the arrival it was supposed to reverse.
|
|
32
|
+
*/
|
|
33
|
+
crossFade?: number;
|
|
34
|
+
/**
|
|
35
|
+
* Interpolate `border-radius` across the flight (default true). Nothing is
|
|
36
|
+
* scaled, so the two ends' own values are the whole story.
|
|
37
|
+
*
|
|
38
|
+
* It rides the CONTENT animation, never the geometry one: a keyframe that
|
|
39
|
+
* lists a property the compositor cannot animate drops that whole animation
|
|
40
|
+
* to the main thread, and the geometry keyframe is the one that must never
|
|
41
|
+
* leave the compositor.
|
|
42
|
+
*/
|
|
43
|
+
radius?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Move the whole screen with the element, not just the element (default off).
|
|
46
|
+
*
|
|
47
|
+
* A plain morph flies ALONE: the element crosses while the screens do
|
|
48
|
+
* whatever their own transition says, which is right when the element is one
|
|
49
|
+
* thing among many. It is wrong when the element IS the navigation — a grid
|
|
50
|
+
* cell opening into a full-screen view. There the eye reads the tap as
|
|
51
|
+
* "the camera moved to this card", and a grid that stays put underneath
|
|
52
|
+
* reads as the card escaping from it.
|
|
53
|
+
*
|
|
54
|
+
* `"screen"` gives the flight a camera: the screen the element is SMALL on
|
|
55
|
+
* (the grid — the departing screen on a push, the arriving one on a pop) is
|
|
56
|
+
* scaled and translated by exactly the zoom that takes the element from one
|
|
57
|
+
* end to the other, so every other card moves as though the viewport had
|
|
58
|
+
* pushed in on the tapped one. Material calls the pattern a container
|
|
59
|
+
* transform; iOS 18 calls its version a zoom transition.
|
|
60
|
+
*
|
|
61
|
+
* It SUPERSEDES that screen's own transform for the length of the flight —
|
|
62
|
+
* the camera IS the screen's motion here, and two authors of one transform
|
|
63
|
+
* is not a thing CSS can compose. Pair it with a transition that does not
|
|
64
|
+
* move the screen itself (`none`, or an opacity-only one); a slide would be
|
|
65
|
+
* replaced rather than combined.
|
|
66
|
+
*/
|
|
67
|
+
carry?: "screen";
|
|
68
|
+
};
|
|
69
|
+
export interface MorphTransition extends Omit<BaseTransition, "name">, MorphTransitionOptions {
|
|
70
|
+
name: MorphTransitionName;
|
|
71
|
+
}
|
|
72
|
+
export declare const MORPH_FROM_VARIANT: Record<TransitionVariant, "initial" | "IDLE-true" | "self">;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Transition } from './typing';
|
|
2
2
|
import { Decorator } from './decorator/typing';
|
|
3
|
+
import { MorphTransition } from './morphTransition/typing';
|
|
3
4
|
import { PartTransition } from './partTransition/typing';
|
|
4
|
-
export default function registerTransitionDefinitions(transitions: Transition[], decorators: Decorator[], partTransitions?: PartTransition[]): () => void;
|
|
5
|
+
export default function registerTransitionDefinitions(transitions: Transition[], decorators: Decorator[], partTransitions?: PartTransition[], morphTransitions?: MorphTransition[]): () => void;
|
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
export declare const MIN_SETTLE_SECONDS = 0.12;
|
|
2
|
+
/**
|
|
3
|
+
* The initial slope a release curve is allowed to reach, as a multiple of its
|
|
4
|
+
* own average speed — the ceiling on "the finger was going fast".
|
|
5
|
+
*
|
|
6
|
+
* It is also what the by-speed length is derived from: a curve that starts at
|
|
7
|
+
* the finger's speed and decelerates to rest covers the remaining distance in
|
|
8
|
+
* `slope x remaining / speed`, not `remaining / speed`. The old formula solved
|
|
9
|
+
* for a motion that never slows down, which no landing does.
|
|
10
|
+
*/
|
|
11
|
+
export declare const RELEASE_LAUNCH_SLOPE = 1.6;
|
|
12
|
+
/**
|
|
13
|
+
* The floor on that slope. A very slow drag with most of the screen left
|
|
14
|
+
* cannot be honored literally — matching 150 px/s over 310px would take two
|
|
15
|
+
* seconds — so the settle does accelerate away from it. It leaves at half its
|
|
16
|
+
* average rather than at 2.25x, which is the difference between the system
|
|
17
|
+
* taking over and the screen being snatched.
|
|
18
|
+
*/
|
|
19
|
+
export declare const MIN_LAUNCH_SLOPE = 0.5;
|
|
2
20
|
export declare const MIN_REVERSAL_SECONDS = 0.28;
|
|
3
21
|
export interface SwipeSettleInput {
|
|
4
22
|
remainingPx: number;
|
|
@@ -6,6 +24,69 @@ export interface SwipeSettleInput {
|
|
|
6
24
|
velocityPxPerSecond: number;
|
|
7
25
|
reversing?: boolean;
|
|
8
26
|
authoredSeconds: number;
|
|
27
|
+
/**
|
|
28
|
+
* The authored curve's control points. Given them, the distance term is the
|
|
29
|
+
* time that curve itself spends on the stretch that is left; without them it
|
|
30
|
+
* falls back to reading the motion as linear, which is what this used to do
|
|
31
|
+
* for every transition.
|
|
32
|
+
*/
|
|
33
|
+
authoredEase?: readonly [number, number, number, number];
|
|
9
34
|
minSeconds?: number;
|
|
10
35
|
}
|
|
11
|
-
|
|
36
|
+
/**
|
|
37
|
+
* How long the authored curve takes to travel its LAST `1 - progress` — the
|
|
38
|
+
* stretch a release that let go at `progress` still has to cover.
|
|
39
|
+
*
|
|
40
|
+
* The curve maps time to distance, so this inverts it: find the time at which
|
|
41
|
+
* it has covered `progress`, and return what is left of the duration. Both
|
|
42
|
+
* searches are on a monotone function.
|
|
43
|
+
*/
|
|
44
|
+
export declare const authoredTailSeconds: (progress: number, authoredSeconds: number, ease: readonly [number, number, number, number]) => number;
|
|
45
|
+
export declare const swipeSettleSeconds: ({ remainingPx, spanPx, velocityPxPerSecond, authoredSeconds, authoredEase, reversing, minSeconds }: SwipeSettleInput) => number;
|
|
46
|
+
/**
|
|
47
|
+
* The release curve's normalized initial slope: the speed the settle leaves at,
|
|
48
|
+
* as a multiple of its own average. `velocity x seconds / remaining` is exactly
|
|
49
|
+
* the finger's speed expressed in those units.
|
|
50
|
+
*
|
|
51
|
+
* ONE RULE, INCLUDING THE CANCEL. A reversal's finger was going the other way,
|
|
52
|
+
* so the speed it contributes to the settle's own direction is not its own
|
|
53
|
+
* speed — it is zero or less. Zero is what this reads it as, which puts every
|
|
54
|
+
* reversal on the floor: the screen is standing still when the settle begins,
|
|
55
|
+
* and it opens like something standing still.
|
|
56
|
+
*
|
|
57
|
+
* Full velocity continuity for a reversal would mean OVERSHOOT — the screen
|
|
58
|
+
* carrying on the way the finger was pushing for a hair before it returns,
|
|
59
|
+
* which is what a real spring does. That is a different primitive, not a
|
|
60
|
+
* re-aimed bezier, and it is deliberately not attempted here. Clamping at zero
|
|
61
|
+
* is the closest a monotone curve gets.
|
|
62
|
+
*/
|
|
63
|
+
export declare const releaseLaunchSlope: ({ remainingPx, velocityPxPerSecond, seconds, authoredSlope, reversing }: {
|
|
64
|
+
remainingPx: number;
|
|
65
|
+
velocityPxPerSecond: number;
|
|
66
|
+
seconds: number;
|
|
67
|
+
/**
|
|
68
|
+
* The opening slope the transition's author drew. The floor never rises
|
|
69
|
+
* above it: a release that the gesture cannot support must not come out
|
|
70
|
+
* HARDER than the authored motion — the floor is there to stop a crawl, not
|
|
71
|
+
* to add energy the author did not ask for. The ceiling is not capped this
|
|
72
|
+
* way; a finger genuinely moving fast should leave fast, even out of a curve
|
|
73
|
+
* drawn to open gently, or the screen reads as braking the moment it is let
|
|
74
|
+
* go.
|
|
75
|
+
*/
|
|
76
|
+
authoredSlope?: number;
|
|
77
|
+
reversing?: boolean;
|
|
78
|
+
}) => number | null;
|
|
79
|
+
/**
|
|
80
|
+
* Re-aim an authored cubic-bezier so it LEAVES at `slope` times its average
|
|
81
|
+
* speed, keeping its x handles and its landing.
|
|
82
|
+
*
|
|
83
|
+
* Only `y1` moves. `x1`/`x2` are the authored ones, so the result is still a
|
|
84
|
+
* valid CSS timing function by construction (x monotonicity is a property of
|
|
85
|
+
* the x handles alone) and still lands the way the transition's author drew it
|
|
86
|
+
* — the release differs from the authored curve exactly where the gesture
|
|
87
|
+
* differs from a standing start, and nowhere else.
|
|
88
|
+
*
|
|
89
|
+
* `y1` is capped below 1 so the curve cannot overshoot its own target; where a
|
|
90
|
+
* steep slope would need more, `x1` shrinks to buy it instead.
|
|
91
|
+
*/
|
|
92
|
+
export declare const reaimReleaseEase: (authored: readonly [number, number, number, number], slope: number) => [number, number, number, number];
|
|
@@ -30,7 +30,7 @@ export interface SwipeInfo {
|
|
|
30
30
|
export type SwipeAnimate = (target: HTMLElement, value: TransitionTarget, options?: AnimationOptions) => Promise<void>;
|
|
31
31
|
export type TransitionOptions = {
|
|
32
32
|
decoratorName?: DecoratorName;
|
|
33
|
-
driver?: "native"
|
|
33
|
+
driver?: "native";
|
|
34
34
|
swipeDirection: "x" | "y";
|
|
35
35
|
onSwipeStart: (event: PointerEvent, info: SwipeInfo, options: {
|
|
36
36
|
animate: SwipeAnimate;
|
|
@@ -52,7 +52,7 @@ export type TransitionOptions = {
|
|
|
52
52
|
}) => Promise<boolean>;
|
|
53
53
|
} | {
|
|
54
54
|
decoratorName?: DecoratorName;
|
|
55
|
-
driver?: "native"
|
|
55
|
+
driver?: "native";
|
|
56
56
|
swipeDirection?: never;
|
|
57
57
|
};
|
|
58
58
|
export interface BaseTransition {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flemo/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Framework-agnostic primitives for flemo: history, navigation, transitions, task manager.",
|
|
5
5
|
"main": "./dist/index.mjs",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -33,20 +33,20 @@
|
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"path-to-regexp": "^8.4.2",
|
|
36
|
-
"zustand": "^5.0.
|
|
36
|
+
"zustand": "^5.0.15"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
+
"@flemo/eslint-config": "0.0.0",
|
|
40
|
+
"@flemo/tsconfig": "0.0.0",
|
|
39
41
|
"@types/node": "^24.13.1",
|
|
40
|
-
"@vitest/coverage-v8": "^4.1.
|
|
42
|
+
"@vitest/coverage-v8": "^4.1.11",
|
|
41
43
|
"csstype": "^3.2.3",
|
|
42
44
|
"eslint": "^9.39.5",
|
|
43
45
|
"jsdom": "^29.1.1",
|
|
44
46
|
"typescript": "^6.0.3",
|
|
45
|
-
"vite": "^8.2.
|
|
47
|
+
"vite": "^8.2.2",
|
|
46
48
|
"vite-plugin-dts": "^5.0.3",
|
|
47
|
-
"vitest": "^4.1.
|
|
48
|
-
"@flemo/tsconfig": "0.0.0",
|
|
49
|
-
"@flemo/eslint-config": "0.0.0"
|
|
49
|
+
"vitest": "^4.1.11"
|
|
50
50
|
},
|
|
51
51
|
"publishConfig": {
|
|
52
52
|
"access": "public"
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export declare const FORCE_PIN_TTL_MS: number;
|
|
2
|
-
export interface DriverPolicy {
|
|
3
|
-
playerAllowed: () => boolean;
|
|
4
|
-
pinnedDriver: () => "css" | "raf" | null;
|
|
5
|
-
}
|
|
6
|
-
export declare const detectBlinkEngine: () => boolean;
|
|
7
|
-
export declare const isLegacyAndroidBlink: () => boolean;
|
|
8
|
-
export declare const isDesktopMacWebKit: () => boolean;
|
|
9
|
-
export declare const isDesktopBlink: () => boolean;
|
|
10
|
-
export declare const createDriverPolicy: (playerByDefault?: boolean) => DriverPolicy;
|
|
11
|
-
declare const driverPolicy: DriverPolicy;
|
|
12
|
-
export default driverPolicy;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { VariantMotion } from '../../transition/variantMotion';
|
|
2
|
-
import { PerceptualBox } from './perceptualSpan';
|
|
3
|
-
export declare const SNAP_VELOCITY_DEVICE_PX_PER_FRAME = 40;
|
|
4
|
-
export declare const SNAP_BAND_MAX_DEVICE_PX = 480;
|
|
5
|
-
export declare const snappedEasingForMotion: (motion: VariantMotion, box: PerceptualBox, devicePixelRatio: number) => string | null;
|
|
6
|
-
export declare const governedEasingForMotion: (motion: VariantMotion, box: PerceptualBox, devicePixelRatio: number, frameIntervalMs: number) => string | null;
|
|
7
|
-
export declare const governedBezierForMotion: (motion: VariantMotion | null, box: PerceptualBox, devicePixelRatio: number, frameIntervalMs: number) => {
|
|
8
|
-
easing: string;
|
|
9
|
-
durationMs: number;
|
|
10
|
-
} | null;
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { Transition } from '../../transition/typing';
|
|
2
|
-
import { VariantMotion } from '../../transition/variantMotion';
|
|
3
|
-
import { PerceptualBox } from './perceptualSpan';
|
|
4
|
-
export declare const NATIVE_PEAK_CSS_PX_PER_FRAME = 6;
|
|
5
|
-
export declare const peakTranslationPxPerFrame: (motion: VariantMotion, box: PerceptualBox) => number | null;
|
|
6
|
-
export type MotionDriverKind = "native" | "player";
|
|
7
|
-
export declare const classifyTransitionDriver: (transition: Transition, _status: string, _box: PerceptualBox) => MotionDriverKind;
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { VariantMotion } from '../../transition/variantMotion';
|
|
2
|
-
export { resetSessionOverrideCachesForTests } from './diagnosticFlags';
|
|
3
|
-
export declare const isPlayerDrivable: (motion: VariantMotion) => boolean;
|
|
4
|
-
export interface SnapMemory {
|
|
5
|
-
x: number | null;
|
|
6
|
-
y: number | null;
|
|
7
|
-
landingX?: number | null;
|
|
8
|
-
landingY?: number | null;
|
|
9
|
-
writtenX?: number | null;
|
|
10
|
-
writtenY?: number | null;
|
|
11
|
-
pendingLanding?: boolean;
|
|
12
|
-
glide?: boolean;
|
|
13
|
-
}
|
|
14
|
-
export declare const learnedFrameIntervalMs: () => number;
|
|
15
|
-
export declare const reportDisplayIntervalMs: (intervalMs: number) => void;
|
|
16
|
-
export interface PlayerScheduler {
|
|
17
|
-
request: (callback: (time: number) => void) => number;
|
|
18
|
-
cancel: (handle: number) => void;
|
|
19
|
-
devicePixelRatio: () => number;
|
|
20
|
-
}
|
|
21
|
-
export interface TrackInput {
|
|
22
|
-
element: HTMLElement;
|
|
23
|
-
motion: VariantMotion;
|
|
24
|
-
role: "active" | "passive";
|
|
25
|
-
onComplete?: () => void;
|
|
26
|
-
status?: string;
|
|
27
|
-
}
|
|
28
|
-
export interface TransitionPlayerRegistry {
|
|
29
|
-
join: (taskId: string, input: TrackInput) => (() => void) | null;
|
|
30
|
-
dispose: (taskId: string) => void;
|
|
31
|
-
onFrameGap?: (gapMs: number) => void;
|
|
32
|
-
}
|
|
33
|
-
export declare const createTransitionPlayerRegistry: (scheduler?: PlayerScheduler) => TransitionPlayerRegistry;
|
|
34
|
-
declare const transitionPlayers: TransitionPlayerRegistry;
|
|
35
|
-
export default transitionPlayers;
|
|
36
|
-
declare global {
|
|
37
|
-
interface Window {
|
|
38
|
-
__flemoPlayerGaps?: number[];
|
|
39
|
-
}
|
|
40
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/dist/core/engine/__tests__/{transitionPlayer.test.d.ts → flightParticipants.test.d.ts}
RENAMED
|
File without changes
|
|
File without changes
|