@motion.page/sdk 1.0.1 → 1.0.3
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/README.md +69 -6
- package/dist/core/Timeline.d.ts +66 -5
- package/dist/easing/index.d.ts +44 -1
- package/dist/index.cjs +5 -7
- package/dist/index.cjs.map +16 -16
- package/dist/index.js +5 -7
- package/dist/index.js.map +16 -16
- package/dist/triggers/CursorTrigger.d.ts +2 -2
- package/dist/triggers/EventTrigger.d.ts +4 -0
- package/dist/triggers/GlobalScrollListener.d.ts +36 -0
- package/dist/triggers/MarkerManager.d.ts +15 -1
- package/dist/triggers/PinManager.d.ts +42 -0
- package/dist/triggers/TriggerManager.d.ts +2 -0
- package/dist/types/index.d.ts +23 -0
- package/dist/utils/FilterParser.d.ts +7 -1
- package/dist/utils/TextSplitter.d.ts +5 -0
- package/dist/utils/getLayoutRect.d.ts +6 -0
- package/package.json +1 -1
|
@@ -29,10 +29,10 @@ export declare class CursorTrigger extends BaseTrigger<CursorConfig> {
|
|
|
29
29
|
private _boundMouseMove?;
|
|
30
30
|
private _boundMouseDown?;
|
|
31
31
|
private _boundMouseUp?;
|
|
32
|
-
private
|
|
32
|
+
private _hoverSelectors;
|
|
33
33
|
private _isHoveringCursorTarget;
|
|
34
34
|
private _boundHoverTargetMoveHandler;
|
|
35
|
-
private
|
|
35
|
+
private _cursorStyleTag;
|
|
36
36
|
private _attributeListeners;
|
|
37
37
|
constructor(timeline: Timeline, config: CursorConfig);
|
|
38
38
|
private _parseStateConfig;
|
|
@@ -23,6 +23,8 @@ export declare class EventTrigger extends BaseTrigger<EventTriggerConfig> {
|
|
|
23
23
|
private _listeners;
|
|
24
24
|
private _isForward;
|
|
25
25
|
private _frozenRects;
|
|
26
|
+
private _snapshotScrollX;
|
|
27
|
+
private _snapshotScrollY;
|
|
26
28
|
private _wasHovering;
|
|
27
29
|
private _hoverLeaveTimeout;
|
|
28
30
|
private _boundMouseMoveHandler;
|
|
@@ -40,6 +42,8 @@ export declare class EventTrigger extends BaseTrigger<EventTriggerConfig> {
|
|
|
40
42
|
* Called by TriggerManager.refreshScrollTriggers() on resize.
|
|
41
43
|
*/
|
|
42
44
|
refresh(): void;
|
|
45
|
+
/** Snapshot frozen rects and the current scroll offset. */
|
|
46
|
+
private _snapshotRects;
|
|
43
47
|
private _resolveTargets;
|
|
44
48
|
private _addHoverListeners;
|
|
45
49
|
private _handleLeaveAction;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GlobalScrollListener
|
|
3
|
+
*
|
|
4
|
+
* Consolidates per-instance scroll listeners into a single listener per scroller.
|
|
5
|
+
* This mirrors GSAP's architecture where one global scroll handler reads scrollY
|
|
6
|
+
* once and dispatches to all active ScrollTrigger instances in a single pass.
|
|
7
|
+
*
|
|
8
|
+
* Benefits:
|
|
9
|
+
* - Eliminates N scroll event listeners (one per ScrollTrigger) → 1 per scroller
|
|
10
|
+
* - For instant scrub: wraps all instance updates in a single runBatched() call,
|
|
11
|
+
* so DOM writes are flushed once instead of N times per scroll event
|
|
12
|
+
* - Reads scrollY once per scroll event, shared across all instances
|
|
13
|
+
*
|
|
14
|
+
* Architecture:
|
|
15
|
+
* - Each unique scroller (window or custom element) gets ONE passive scroll listener
|
|
16
|
+
* - On scroll, all registered callbacks for that scroller run inside a single
|
|
17
|
+
* runBatched() wrapper (batches instant-scrub DOM writes into one flush)
|
|
18
|
+
* - When the last callback for a scroller is removed, the listener is detached
|
|
19
|
+
*/
|
|
20
|
+
type ScrollCallback = () => void;
|
|
21
|
+
/**
|
|
22
|
+
* Register a scroll callback for a given scroller.
|
|
23
|
+
* The first registration for a scroller attaches a single passive scroll listener.
|
|
24
|
+
*/
|
|
25
|
+
export declare function addScrollCallback(scroller: EventTarget, callback: ScrollCallback): void;
|
|
26
|
+
/**
|
|
27
|
+
* Remove a scroll callback for a given scroller.
|
|
28
|
+
* When the last callback is removed, the scroll listener is detached.
|
|
29
|
+
*/
|
|
30
|
+
export declare function removeScrollCallback(scroller: EventTarget, callback: ScrollCallback): void;
|
|
31
|
+
/**
|
|
32
|
+
* Reset all state (for testing only).
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
35
|
+
export declare function _resetGlobalScrollListener(): void;
|
|
36
|
+
export {};
|
|
@@ -25,15 +25,29 @@ export declare class MarkerManager {
|
|
|
25
25
|
private _scroller;
|
|
26
26
|
private _startConfig;
|
|
27
27
|
private _endConfig;
|
|
28
|
+
private _cachedElStartDocTop;
|
|
29
|
+
private _cachedElEndDocTop;
|
|
30
|
+
private _cachedElPositionValid;
|
|
28
31
|
constructor(triggerId: number);
|
|
29
32
|
/**
|
|
30
33
|
* Create debug markers showing trigger positions
|
|
31
34
|
*/
|
|
32
35
|
setup(config: MarkerSetupConfig): void;
|
|
33
36
|
/**
|
|
34
|
-
*
|
|
37
|
+
* Cache element marker positions in document/content coordinates.
|
|
38
|
+
* Called at setup and on refresh. This is the only place getLayoutRect() is called
|
|
39
|
+
* for element markers — the per-frame update() uses cached values instead.
|
|
40
|
+
*/
|
|
41
|
+
private _cacheElementPositions;
|
|
42
|
+
/**
|
|
43
|
+
* Update marker positions on scroll.
|
|
44
|
+
* Uses cached document-relative positions to avoid getLayoutRect() per frame.
|
|
35
45
|
*/
|
|
36
46
|
update(scrollTop: number, triggerElement: HTMLElement | null, viewportHeight: number): void;
|
|
47
|
+
/**
|
|
48
|
+
* Recache element positions after layout changes (resize, refresh).
|
|
49
|
+
*/
|
|
50
|
+
recachePositions(viewportHeight: number): void;
|
|
37
51
|
/**
|
|
38
52
|
* Remove all markers
|
|
39
53
|
*/
|
|
@@ -39,6 +39,7 @@ export declare class PinManager {
|
|
|
39
39
|
private _fixedTop;
|
|
40
40
|
private _fixedLeft;
|
|
41
41
|
private _width;
|
|
42
|
+
private _fixedBreakingAncestors;
|
|
42
43
|
constructor(id: number);
|
|
43
44
|
/**
|
|
44
45
|
* Setup pinning for an element
|
|
@@ -101,6 +102,47 @@ export declare class PinManager {
|
|
|
101
102
|
* Check if using fixed pin strategy
|
|
102
103
|
*/
|
|
103
104
|
isFixedPin(): boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Detect ancestor elements with CSS properties that break position:fixed.
|
|
107
|
+
*
|
|
108
|
+
* Any of these on an ancestor creates a new containing block, causing
|
|
109
|
+
* position:fixed to position relative to that ancestor instead of the
|
|
110
|
+
* viewport — making pinned elements scroll off-screen:
|
|
111
|
+
*
|
|
112
|
+
* - filter (even blur(0px)) — set by animation libraries as initial state
|
|
113
|
+
* - transform (even translate(0)) — set by smooth scroll libraries (Lenis)
|
|
114
|
+
* - will-change: transform/filter/perspective
|
|
115
|
+
* - perspective
|
|
116
|
+
* - contain: paint/layout/strict/content
|
|
117
|
+
* - backdrop-filter
|
|
118
|
+
* - overflow: clip — clips fixed descendants at element's padding box
|
|
119
|
+
*
|
|
120
|
+
* Only needs to run once during first setup (not on refresh).
|
|
121
|
+
*/
|
|
122
|
+
private _detectFixedBreakingAncestors;
|
|
123
|
+
/**
|
|
124
|
+
* Override properties on ancestors that break position:fixed.
|
|
125
|
+
*
|
|
126
|
+
* IMPORTANT: Captures the current inline style value RIGHT BEFORE overriding,
|
|
127
|
+
* not at detection time. This prevents restoring stale values — e.g. if an
|
|
128
|
+
* animation set `filter: blur(5px)` at detection time but has since completed
|
|
129
|
+
* and the SDK cleaned it to `none`, we'd wrongly restore `blur(5px)` on unpin.
|
|
130
|
+
*
|
|
131
|
+
* Safe fallback values:
|
|
132
|
+
* - filter/transform/perspective → 'none'
|
|
133
|
+
* - will-change → 'auto'
|
|
134
|
+
* - contain → 'none'
|
|
135
|
+
* - overflow-x:clip → 'hidden' (still prevents horizontal scrollbar)
|
|
136
|
+
* - overflow-y:clip → 'visible'
|
|
137
|
+
*/
|
|
138
|
+
private _overrideFixedBreakingAncestors;
|
|
139
|
+
/**
|
|
140
|
+
* Restore original values on ancestors that were overridden during pin.
|
|
141
|
+
* The values restored are the ones captured at override time (pin entry),
|
|
142
|
+
* not detection time — so they reflect the element's actual state just
|
|
143
|
+
* before the pin started.
|
|
144
|
+
*/
|
|
145
|
+
private _restoreFixedBreakingAncestors;
|
|
104
146
|
/**
|
|
105
147
|
* Resolve pinSpacing config to a concrete value
|
|
106
148
|
*/
|
|
@@ -13,6 +13,8 @@ import type { Timeline } from '../core/Timeline';
|
|
|
13
13
|
/** Config for page load trigger */
|
|
14
14
|
export interface PageLoadTriggerConfig {
|
|
15
15
|
timing?: 'before' | 'during' | 'after';
|
|
16
|
+
/** When true, the timeline is built but not played — use Motion('name').play() to start it manually */
|
|
17
|
+
paused?: boolean;
|
|
16
18
|
}
|
|
17
19
|
/** Interface that trigger instances must satisfy for cleanup */
|
|
18
20
|
interface TriggerInstance {
|
package/dist/types/index.d.ts
CHANGED
|
@@ -18,6 +18,28 @@ export interface RepeatConfig {
|
|
|
18
18
|
delay?: number;
|
|
19
19
|
yoyo?: boolean;
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Configuration for a Timeline instance
|
|
23
|
+
*/
|
|
24
|
+
export interface TimelineConfig {
|
|
25
|
+
/**
|
|
26
|
+
* Number of times to repeat the entire timeline.
|
|
27
|
+
* Use a number for simple repeats, or RepeatConfig for advanced options.
|
|
28
|
+
* Use -1 for infinite repeat.
|
|
29
|
+
* @example
|
|
30
|
+
* new Timeline('loop', { repeat: -1 })
|
|
31
|
+
* new Timeline('bounce', { repeat: { times: 3, delay: 0.2, yoyo: true } })
|
|
32
|
+
*/
|
|
33
|
+
repeat?: number | RepeatConfig;
|
|
34
|
+
/** Called when the timeline starts playing (first frame with time > 0) */
|
|
35
|
+
onStart?: () => void;
|
|
36
|
+
/** Called every frame with the current progress (0–1) and time (seconds) */
|
|
37
|
+
onUpdate?: (progress: number, time: number) => void;
|
|
38
|
+
/** Called when the timeline completes all repeats */
|
|
39
|
+
onComplete?: () => void;
|
|
40
|
+
/** Called at the end of each repeat cycle */
|
|
41
|
+
onRepeat?: (repeatCount: number) => void;
|
|
42
|
+
}
|
|
21
43
|
/**
|
|
22
44
|
* Stagger configuration for multiple elements
|
|
23
45
|
*/
|
|
@@ -67,6 +89,7 @@ export interface AnimationVars {
|
|
|
67
89
|
paddingBottom?: number | string;
|
|
68
90
|
paddingLeft?: number | string;
|
|
69
91
|
borderRadius?: number | string;
|
|
92
|
+
borderWidth?: number | string;
|
|
70
93
|
fontSize?: number | string;
|
|
71
94
|
lineHeight?: number | string;
|
|
72
95
|
letterSpacing?: number | string;
|
|
@@ -26,7 +26,13 @@ export interface ParsedFilterFunction {
|
|
|
26
26
|
*/
|
|
27
27
|
export declare function parseFilter(filter: string): ParsedFilterFunction[] | null;
|
|
28
28
|
/**
|
|
29
|
-
* Convert parsed filter functions back to CSS filter string
|
|
29
|
+
* Convert parsed filter functions back to CSS filter string.
|
|
30
|
+
*
|
|
31
|
+
* Returns 'none' when all filters are at their identity/default values
|
|
32
|
+
* (e.g. blur(0px), brightness(1)). This is critical because any filter
|
|
33
|
+
* value other than 'none' — even visually invisible ones like blur(0px) —
|
|
34
|
+
* creates a CSS containing block that breaks position:fixed on descendants.
|
|
35
|
+
* This would cause pinned sections to disappear during scroll animations.
|
|
30
36
|
*/
|
|
31
37
|
export declare function filterToString(filters: ParsedFilterFunction[]): string;
|
|
32
38
|
/**
|
|
@@ -41,6 +41,11 @@ export declare class TextSplitter {
|
|
|
41
41
|
private static _splitWordsDom;
|
|
42
42
|
/**
|
|
43
43
|
* Split text nodes into character spans, preserving existing element wrappers.
|
|
44
|
+
*
|
|
45
|
+
* Characters are grouped by word inside implicit wrapper spans with
|
|
46
|
+
* `white-space: nowrap` so the browser never breaks a word across lines
|
|
47
|
+
* (matching GSAP SplitText behaviour). Only the char spans are exposed
|
|
48
|
+
* as animatable elements — the word wrappers are transparent to consumers.
|
|
44
49
|
*/
|
|
45
50
|
private static _splitCharsDom;
|
|
46
51
|
/**
|
|
@@ -11,5 +11,11 @@
|
|
|
11
11
|
* coordinates from getBoundingClientRect(), which would produce incorrect
|
|
12
12
|
* document-relative trigger positions. Temporarily clearing position/top/left/width
|
|
13
13
|
* restores document-flow measurement before reading the rect.
|
|
14
|
+
*
|
|
15
|
+
* Performance notes:
|
|
16
|
+
* - The getComputedStyle() call to detect position:fixed is skipped when we
|
|
17
|
+
* can tell from the inline style alone (fast path for the common case).
|
|
18
|
+
* - No forced reflow after restoring styles — the browser batches style
|
|
19
|
+
* writes and applies them before the next paint automatically.
|
|
14
20
|
*/
|
|
15
21
|
export declare function getLayoutRect(element: Element): DOMRect;
|