chnobli 0.1.10 → 0.1.11

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 (107) hide show
  1. package/dist/animation/Animation.d.ts +2 -1
  2. package/dist/animation/Animation.d.ts.map +1 -1
  3. package/dist/animation/Animation.js +5 -3
  4. package/dist/animation/Animation.js.map +1 -1
  5. package/dist/animator/Animator.d.ts +30 -0
  6. package/dist/animator/Animator.d.ts.map +1 -0
  7. package/dist/animator/Animator.js +97 -0
  8. package/dist/animator/Animator.js.map +1 -0
  9. package/dist/animator/index.d.ts +5 -0
  10. package/dist/animator/index.d.ts.map +1 -0
  11. package/dist/animator/index.js +53 -0
  12. package/dist/animator/index.js.map +1 -0
  13. package/dist/animator/public.d.ts +16 -0
  14. package/dist/animator/public.d.ts.map +1 -0
  15. package/dist/animator/public.js +50 -0
  16. package/dist/animator/public.js.map +1 -0
  17. package/dist/chnobli.d.ts +3 -3
  18. package/dist/chnobli.d.ts.map +1 -1
  19. package/dist/chnobli.js.map +1 -1
  20. package/dist/property/ClassProperty.js +1 -1
  21. package/dist/property/ClassProperty.js.map +1 -1
  22. package/dist/property/TransformXYProperty.d.ts.map +1 -1
  23. package/dist/scroll/Scroll.d.ts +24 -3
  24. package/dist/scroll/Scroll.d.ts.map +1 -1
  25. package/dist/scroll/Scroll.js +155 -43
  26. package/dist/scroll/Scroll.js.map +1 -1
  27. package/dist/scroll/ScrollEvent.d.ts.map +1 -1
  28. package/dist/scroll/ScrollEvent.js +1 -0
  29. package/dist/scroll/ScrollEvent.js.map +1 -1
  30. package/dist/scroll/index.d.ts +2 -0
  31. package/dist/scroll/index.d.ts.map +1 -1
  32. package/dist/scroll/index.js +1 -0
  33. package/dist/scroll/index.js.map +1 -1
  34. package/dist/scroll/public.d.ts +19 -1
  35. package/dist/scroll/public.d.ts.map +1 -1
  36. package/dist/scroll/public.js +26 -1
  37. package/dist/scroll/public.js.map +1 -1
  38. package/dist/target/DomTarget.js +1 -1
  39. package/dist/target/DomTarget.js.map +1 -1
  40. package/dist/target/ObjectTarget.d.ts +11 -10
  41. package/dist/target/ObjectTarget.d.ts.map +1 -1
  42. package/dist/target/ObjectTarget.js +20 -13
  43. package/dist/target/ObjectTarget.js.map +1 -1
  44. package/dist/timeline/Timeline.d.ts +2 -1
  45. package/dist/timeline/Timeline.d.ts.map +1 -1
  46. package/dist/timeline/Timeline.js +4 -4
  47. package/dist/timeline/Timeline.js.map +1 -1
  48. package/dist/timeline/public.d.ts +11 -4
  49. package/dist/timeline/public.d.ts.map +1 -1
  50. package/dist/timeline/public.js +19 -11
  51. package/dist/timeline/public.js.map +1 -1
  52. package/dist/timing/AnimationFrameTicker.d.ts.map +1 -1
  53. package/dist/timing/AnimationFrameTicker.js +5 -1
  54. package/dist/timing/AnimationFrameTicker.js.map +1 -1
  55. package/dist/timing/TestTicker.d.ts.map +1 -1
  56. package/dist/timing/TestTicker.js +5 -1
  57. package/dist/timing/TestTicker.js.map +1 -1
  58. package/dist/timing/Ticker.d.ts +4 -2
  59. package/dist/timing/Ticker.d.ts.map +1 -1
  60. package/dist/timing/Timing.d.ts +47 -2
  61. package/dist/timing/Timing.d.ts.map +1 -1
  62. package/dist/timing/Timing.js +118 -84
  63. package/dist/timing/Timing.js.map +1 -1
  64. package/dist/utils/Events.js +1 -1
  65. package/dist/utils/Events.js.map +1 -1
  66. package/dist/utils/motionpath.js +5 -5
  67. package/dist/utils/motionpath.js.map +1 -1
  68. package/dist/utils/utils.d.ts.map +1 -1
  69. package/dist/utils/utils.js +0 -8
  70. package/dist/utils/utils.js.map +1 -1
  71. package/dist/values/ColorValue.js +1 -0
  72. package/dist/values/ColorValue.js.map +1 -1
  73. package/dist/values/Value.js +1 -1
  74. package/dist/values/Value.js.map +1 -1
  75. package/eslint.config.js +23 -0
  76. package/package.json +10 -3
  77. package/src/animation/Animation.ts +6 -3
  78. package/src/animator/Animator.ts +130 -0
  79. package/src/animator/index.ts +56 -0
  80. package/src/animator/public.ts +66 -0
  81. package/src/chnobli.ts +3 -2
  82. package/src/property/ClassProperty.ts +1 -1
  83. package/src/property/TransformXYProperty.ts +1 -1
  84. package/src/scroll/Scroll.ts +202 -51
  85. package/src/scroll/ScrollEvent.ts +1 -0
  86. package/src/scroll/index.ts +3 -0
  87. package/src/scroll/public.ts +35 -2
  88. package/src/target/DomTarget.ts +1 -1
  89. package/src/target/ObjectTarget.ts +19 -13
  90. package/src/tests/properties.test.ts +44 -3
  91. package/src/tests/timeline.test.ts +1 -1
  92. package/src/tests/timing.test.ts +32 -0
  93. package/src/tests/usecases.test.ts +40 -2
  94. package/src/tests/values.test.ts +9 -9
  95. package/src/timeline/Timeline.ts +5 -4
  96. package/src/timeline/public.ts +34 -12
  97. package/src/timing/AnimationFrameTicker.ts +6 -1
  98. package/src/timing/TestTicker.ts +7 -1
  99. package/src/timing/Ticker.ts +5 -1
  100. package/src/timing/Timing.ts +127 -91
  101. package/src/utils/Events.ts +1 -1
  102. package/src/utils/motionpath.ts +5 -5
  103. package/src/utils/utils.ts +0 -10
  104. package/src/values/ColorValue.ts +1 -0
  105. package/src/values/Value.ts +1 -1
  106. package/.eslintrc.cjs +0 -39
  107. package/src/animator.js +0 -187
@@ -0,0 +1,130 @@
1
+ import Property, { newProperty } from '../property/Property.js';
2
+ import { Target } from '../target/Target.js';
3
+ import Ticker from '../timing/Ticker.js';
4
+ import Timing, { STATE_AFTER } from '../timing/Timing.js';
5
+
6
+ export type Settings = {
7
+ duration: number;
8
+ ease?: (t: number) => number;
9
+ };
10
+
11
+ /*
12
+
13
+ const opacity = animator(obj, {
14
+ duration: 200,
15
+ ease: sinInOut
16
+ });
17
+
18
+ opacity.set({ opacity: 0 });
19
+
20
+ opacity.to({ opacity: 1 });
21
+ opacity.to({ opacity: 2 }, 1000);
22
+ */
23
+
24
+ export default class Animator {
25
+ setts: Settings;
26
+ target: Target;
27
+ private props: Map<string, PropertyAnimator<any>>;
28
+
29
+ private ticker: Ticker;
30
+
31
+ constructor(target: any, ticker: Ticker, setts: Settings) {
32
+ this.setts = setts;
33
+ this.target = ticker.registerTarget(target);
34
+
35
+ this.ticker = ticker;
36
+
37
+ this.props = new Map();
38
+ }
39
+
40
+ private getProp(name: string): PropertyAnimator<any> {
41
+ const prop = this.props.get(name);
42
+ if (prop) return prop;
43
+
44
+ const newProp = new PropertyAnimator(name, this.setts, this.target);
45
+ this.props.set(name, newProp);
46
+ return newProp;
47
+ }
48
+
49
+ set(props: Record<string, any>) {
50
+ for (const prop in props) {
51
+ const propAni = this.getProp(prop);
52
+ console.log('got prop ani', propAni);
53
+ propAni.set(this.target, props[prop]);
54
+ console.log('got prop ani', propAni);
55
+ }
56
+ }
57
+
58
+ to(props: Record<string, any>, duration?: number) {
59
+ for (const prop in props) {
60
+ const propAni = this.getProp(prop);
61
+ propAni.to(this.target, props[prop], duration);
62
+ }
63
+ }
64
+
65
+ /// returns if the ticker should keep running
66
+ _tick(change: number): boolean {
67
+ let shouldStop = true;
68
+
69
+ for (const prop of this.props.values()) {
70
+ prop.advance(change);
71
+ prop.render(this.target);
72
+
73
+ if (prop.timing.state < STATE_AFTER) {
74
+ shouldStop = false;
75
+ }
76
+ }
77
+
78
+ return !shouldStop;
79
+ }
80
+ }
81
+
82
+ export class PropertyAnimator<V> {
83
+ prop: Property<V>;
84
+ timing: Timing;
85
+
86
+ private initialized: boolean;
87
+
88
+ constructor(prop: string, setts: Settings, target: Target) {
89
+ this.prop = newProperty(prop, target.type());
90
+
91
+ this.timing = new Timing(setts);
92
+ this.initialized = false;
93
+ }
94
+
95
+ set(target: Target, value: any) {
96
+ const val = this.prop.parseValue(value);
97
+
98
+ this.prop.init(target, val, val);
99
+
100
+ this.timing.seek(2);
101
+ }
102
+
103
+ to(target: Target, value: any, duration?: number) {
104
+ const val = this.prop.parseValue(value);
105
+
106
+ let current = null;
107
+ if (this.initialized) {
108
+ current = this.prop.interpolate(this.timing.position);
109
+ }
110
+
111
+ this.prop.init(target, current, val);
112
+ this.initialized = true;
113
+
114
+ this.timing.seek(0);
115
+ if (typeof duration === 'number') {
116
+ this.timing.setDuration(duration);
117
+ }
118
+ }
119
+
120
+ advance(change: number) {
121
+ this.timing.advance(change);
122
+ }
123
+
124
+ // call advance first
125
+ render(target: Target) {
126
+ const pos = this.timing.position;
127
+
128
+ this.prop.setValue(target, this.prop.interpolate(pos));
129
+ }
130
+ }
@@ -0,0 +1,56 @@
1
+ /*
2
+
3
+ const obj = { opacity: 1 };
4
+ // maybe we could even have stagger?
5
+ const opacity = animator(obj, {
6
+ // initial value
7
+ // might also be able to be set with stagger?
8
+ // for example
9
+ opacity: 1,
10
+
11
+ duration: 200,
12
+ ease: sineInOut
13
+ });
14
+
15
+ // or maybe instead
16
+
17
+ const animator = animator();
18
+ animator.add(obj, {
19
+ opacity: 1,
20
+ duration: 200,
21
+ ease: sineInOut
22
+ });
23
+
24
+ // what is the reason why we would wan't one animator with
25
+ // multiple objects with different timings
26
+ // could we not just use multiple animators
27
+
28
+
29
+ opacity.set(obj, { opacity: 0 });
30
+
31
+ let's make the most basic animator first
32
+
33
+
34
+ const opacity = animator(obj, {
35
+ duration: 200,
36
+ ease: sinInOut
37
+ });
38
+
39
+ opacity.set({ opacity: 0 });
40
+
41
+ opacity.to({ opacity: 1 });
42
+ opacity.to({ opacity: 2 }, 1000);
43
+
44
+
45
+
46
+
47
+ */
48
+
49
+ import Animator, { AnimatorProps } from './public.js';
50
+
51
+ export { Animator };
52
+ export type { AnimatorProps };
53
+
54
+ export function animator(target: any, props?: AnimatorProps): Animator {
55
+ return new Animator(target, props);
56
+ }
@@ -0,0 +1,66 @@
1
+ /*
2
+ set,
3
+ to,
4
+ */
5
+
6
+ import AnimationFrameTicker from '../timing/AnimationFrameTicker.js';
7
+ import Ticker from '../timing/Ticker.js';
8
+ import Events from '../utils/Events.js';
9
+ import Animator from './Animator.js';
10
+
11
+ export type AnimatorProps = {
12
+ duration?: number;
13
+ ease?: (t: number) => number;
14
+ };
15
+
16
+ export default class PublicAnimator {
17
+ private ticker: Ticker;
18
+ private inner: Animator;
19
+ private runningTicker: any;
20
+ private events: Events;
21
+
22
+ constructor(target: any, props: AnimatorProps = {}) {
23
+ this.ticker = AnimationFrameTicker.global();
24
+ this.inner = new Animator(target, this.ticker, {
25
+ duration: props.duration ?? 1000,
26
+ ease: props.ease,
27
+ });
28
+ this.events = new Events();
29
+ }
30
+
31
+ set(props: Record<string, any>): this {
32
+ this.inner.set(props);
33
+ this.startTicker();
34
+
35
+ return this;
36
+ }
37
+
38
+ to(props: Record<string, any>, duration?: number): this {
39
+ this.inner.to(props, duration);
40
+ this.startTicker();
41
+
42
+ return this;
43
+ }
44
+
45
+ // on: update
46
+ on(ev: string, fn: (...args: any[]) => void): () => void {
47
+ return this.events.add(ev, fn);
48
+ }
49
+
50
+ private startTicker() {
51
+ if (this.runningTicker) return;
52
+
53
+ this.runningTicker = this.ticker.add((change, opts) => {
54
+ const keepRunning = this.inner._tick(change);
55
+
56
+ opts.onApplied(() => {
57
+ this.events.trigger('update');
58
+ });
59
+
60
+ if (!keepRunning) {
61
+ opts.remove();
62
+ this.runningTicker = null;
63
+ }
64
+ });
65
+ }
66
+ }
package/src/chnobli.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  import Animation, { AnimationProps } from './animation/public.js';
2
- import Timeline from './timeline/public.js';
2
+ import Timeline, { TimelineProps } from './timeline/public.js';
3
3
  import Stagger, { type StaggerValue } from './stagger/stagger.js';
4
4
  import type { Targets, AnimationTarget } from './target/Target.js';
5
5
 
6
6
  export type {
7
7
  Animation,
8
8
  Timeline,
9
+ TimelineProps,
9
10
  Stagger,
10
11
  Targets,
11
12
  AnimationTarget,
@@ -28,7 +29,7 @@ export function animate(
28
29
  return new Animation(targets, props);
29
30
  }
30
31
 
31
- export function timeline(props: Record<string, any> = {}): Timeline {
32
+ export function timeline(props: TimelineProps = {}): Timeline {
32
33
  return new Timeline(props);
33
34
  }
34
35
 
@@ -77,7 +77,7 @@ export default class ClassProperty implements Property<string[], Interpolated> {
77
77
  * and in reverse add it at pos 1
78
78
  */
79
79
 
80
- let obj: Interpolated = {
80
+ const obj: Interpolated = {
81
81
  add: [],
82
82
  remove: [],
83
83
  };
@@ -1,5 +1,5 @@
1
1
  import Value from '../values/Value.js';
2
- import Property, { ParseableValue } from './Property.js';
2
+ import Property from './Property.js';
3
3
  import { Target } from '../target/Target.js';
4
4
 
5
5
  export type XYValue = {
@@ -1,7 +1,18 @@
1
- import PublicTimeline, { Offset } from '../timeline/public.js';
1
+ import ResponsiveEvent from '../responsive/ResponsiveEvent.js';
2
+ import PublicTimeline from '../timeline/public.js';
3
+ import Events from '../utils/Events.js';
2
4
  import { pageOffset } from '../utils/utils.js';
3
5
  import ScrollEvent from './ScrollEvent.js';
4
6
 
7
+ export type DestroyOptions = {
8
+ /// defaults to true
9
+ timelines?: boolean;
10
+ };
11
+
12
+ const DEF_DESTROY_OPTS: DestroyOptions = {
13
+ timelines: true,
14
+ };
15
+
5
16
  /*
6
17
  run timelines based on the scroll position
7
18
 
@@ -54,11 +65,13 @@ export type ScrollTrigger =
54
65
 
55
66
  export type OffsetValue = 'top' | 'center' | 'bottom' | number;
56
67
 
68
+ export type State = 'before' | 'in' | 'after';
69
+
57
70
  export type ParsedScrollTrigger = {
58
71
  target: HTMLElement;
59
72
  offset: number;
60
73
  view: number;
61
- position: Position;
74
+ position: Position | undefined;
62
75
  };
63
76
 
64
77
  export type ScrollOffset = {
@@ -72,35 +85,45 @@ export type ScrollOffset = {
72
85
 
73
86
  export type Position = number | string;
74
87
 
88
+ type LastSeek = {
89
+ pos: number;
90
+ state: State;
91
+ };
92
+
75
93
  export default class ScrollTimeline {
76
94
  private _initialized: boolean;
77
- private _globalEvent: ScrollEvent;
78
- private _rmEvent: () => void;
95
+ private _globalEvent: ScrollEvent | null;
96
+ private _scrollEvent: () => void;
97
+ private _responsiveEvent: any;
79
98
 
80
99
  private _triggers: ParsedScrollTrigger[];
100
+ private _events: Events;
101
+ private lastEvPos: number;
81
102
  private timelines: PublicTimeline[];
103
+ private state: State;
104
+ private lastSeek: LastSeek | undefined;
82
105
  offsets: ScrollOffset[];
83
106
 
107
+ private debugMarkers: HTMLElement[];
108
+ private debugPrefix?: string;
109
+
84
110
  constructor() {
85
111
  this._initialized = false;
86
112
  this._globalEvent = ScrollEvent.global();
87
- this._rmEvent = this._globalEvent.add(y => this._onScroll(y)).remove;
113
+ this._scrollEvent =
114
+ this._globalEvent?.add(y => this._onScroll(y)).remove ?? (() => {});
115
+ this._responsiveEvent = ResponsiveEvent.global()?.add((a, b) => {
116
+ this._onResponsive(a, b);
117
+ });
88
118
 
89
119
  this._triggers = [];
120
+ this._events = new Events();
121
+ this.lastEvPos = NaN;
90
122
  this.timelines = [];
123
+ this.state = 'in';
91
124
  this.offsets = [];
92
125
 
93
- // this.timeline = timeline;
94
- // this._triggers = triggers.map(parseTrigger);
95
- // this.offsets = this._triggers.map(t => {
96
- // return {
97
- // y: 0,
98
- // view: t.view,
99
- // };
100
- // });
101
-
102
- // if (this.offsets.length < 2)
103
- // throw new Error('scroll timeline needs at least two triggers');
126
+ this.debugMarkers = [];
104
127
  }
105
128
 
106
129
  /**
@@ -120,21 +143,38 @@ export default class ScrollTimeline {
120
143
  this.timelines.push(timeline);
121
144
  }
122
145
 
123
- init() {
146
+ on(event: string, fn: (...args: any[]) => void): () => void {
147
+ return this._events.add(event, fn);
148
+ }
149
+
150
+ /// Returns true if the init function was executed
151
+ init(): boolean {
152
+ if (this._initialized) return false;
153
+
154
+ this._initialized = true;
155
+
124
156
  // todo we need to calculate the position for each timeline
125
157
  //
126
158
  // calculate the positions and offsets
127
159
  // if we are missing one extend them
128
160
 
129
- let previousY = -1;
130
-
131
- this.offsets = this._triggers.map(t => {
132
- const offset = pageOffset(t.target);
161
+ if (this._triggers.length < 1)
162
+ throw new Error('scroll timeline needs at least one trigger');
133
163
 
134
- const y = offset.top + offset.height * t.offset;
164
+ if (this._triggers.length === 1) {
165
+ this._triggers.push({
166
+ target: this._triggers[0].target,
167
+ offset: 1,
168
+ view: 1,
169
+ position: 1,
170
+ });
171
+ }
135
172
 
136
- if (y < previousY) throw new Error('offsets are not in order');
173
+ const positionStep = 1 / (this._triggers.length - 1);
137
174
 
175
+ // first calculate position and view
176
+ let prevPos = 0;
177
+ this.offsets = this._triggers.map((t, i) => {
138
178
  let position;
139
179
  if (typeof t.position === 'string') {
140
180
  if (this.timelines.length !== 1)
@@ -143,59 +183,170 @@ export default class ScrollTimeline {
143
183
  );
144
184
 
145
185
  position = this.timelines[0].labelPosition(t.position);
146
- } else if (t.position >= 0 || t.position <= 1) {
186
+ } else if (typeof t.position === 'number') {
147
187
  position = t.position;
148
188
  } else {
149
- throw new Error('position should be between 0 and 1');
189
+ position = i * positionStep;
150
190
  }
151
191
 
192
+ if (position < prevPos)
193
+ throw new Error('positions are not in order');
194
+ prevPos = position;
195
+
152
196
  return {
153
- y,
197
+ y: 0,
154
198
  view: t.view,
155
199
  position,
156
200
  };
157
201
  });
158
202
 
159
- if (this.offsets.length < 1)
160
- throw new Error('scroll timeline needs at least one trigger');
203
+ this.initY();
161
204
 
162
- if (this.offsets.length === 1) {
163
- this.offsets.push({
164
- y:
165
- this.offsets[0].y +
166
- pageOffset(this._triggers[0].target).height,
167
- view: 1,
168
- position: 1,
169
- });
205
+ return true;
206
+ }
207
+
208
+ private initY() {
209
+ let previousY = -1;
210
+ this.offsets.forEach((offset, i) => {
211
+ const t = this._triggers[i];
212
+
213
+ const pOffset = pageOffset(t.target);
214
+ const y = pOffset.top + pOffset.height * t.offset;
215
+
216
+ if (y < previousY) throw new Error('offsets are not in order');
217
+ previousY = y;
218
+
219
+ offset.y = y;
220
+ });
221
+ }
222
+
223
+ update() {
224
+ // execute initY to check if elements have moved
225
+ if (!this.init()) this.initY();
226
+
227
+ // todo this position should come from the GlobalEvent
228
+ this._onScroll({
229
+ y: window.scrollY,
230
+ height: window.innerHeight,
231
+ });
232
+ }
233
+
234
+ destroy(opts: DestroyOptions = {}) {
235
+ opts = { ...DEF_DESTROY_OPTS, ...opts };
236
+
237
+ this._scrollEvent();
238
+ this._events.destroy();
239
+ this._responsiveEvent?.remove();
240
+
241
+ if (opts.timelines) {
242
+ for (const timeline of this.timelines) {
243
+ timeline.destroy();
244
+ }
245
+ }
246
+
247
+ for (const marker of this.debugMarkers) {
248
+ marker.remove();
170
249
  }
250
+ this.debugMarkers = [];
251
+ }
252
+
253
+ debug(prefix?: string) {
254
+ this.init();
255
+
256
+ this.debugPrefix = prefix;
257
+
258
+ const height = window.innerHeight;
259
+
260
+ this.offsets.forEach((offset, i) => {
261
+ const y = offset.y - height * offset.view;
262
+
263
+ const marker = document.createElement('span');
264
+ marker.textContent =
265
+ (prefix ? prefix + ' ' : '') + i + ': ' + offset.position;
266
+ marker.style.position = 'absolute';
267
+ marker.style.display = 'block';
268
+ marker.style.right = '0';
269
+ marker.style.top = y + 'px';
270
+ marker.style.minWidth = '50px';
271
+ marker.style.height = '2px';
272
+ marker.style.paddingRight = '10px';
273
+ marker.style.backgroundColor = 'red';
274
+ marker.style.zIndex = '100000';
275
+
276
+ document.body.appendChild(marker);
277
+ this.debugMarkers.push(marker);
278
+ });
171
279
  }
172
280
 
173
281
  private _onScroll({ y, height }: { y: number; height: number }) {
174
- if (!this._initialized) {
175
- this.init();
176
- this._initialized = true;
282
+ this.init();
283
+
284
+ const pos = this.calcPosition({ y, height });
285
+ const clampPos = Math.min(1, Math.max(0, pos));
286
+ const state = pos < 0 ? 'before' : pos > 1 ? 'after' : 'in';
287
+
288
+ // we need to trigger once
289
+ // if the pos is not the same and but pos can have 3 states
290
+ // under (<0), in (0-1) or over (>1)
291
+ // each state should be triggered once
292
+ if (this.lastSeek?.pos === clampPos && this.lastSeek?.state === state) {
293
+ return;
177
294
  }
178
295
 
296
+ this.lastSeek = { pos: clampPos, state };
297
+
298
+ this._events.trigger('update', clampPos, state);
299
+
300
+ for (const timeline of this.timelines) {
301
+ timeline.seek(pos);
302
+ }
303
+ }
304
+
305
+ /**
306
+ * @ignore
307
+ */
308
+ private _onResponsive(
309
+ _a: { width: number; height: number },
310
+ _b: { remove: () => void },
311
+ ) {
312
+ this.update();
313
+
314
+ // reposition debug Markers
315
+ if (this.debugMarkers.length) {
316
+ for (const marker of this.debugMarkers) {
317
+ marker.remove();
318
+ }
319
+
320
+ this.debug(this.debugPrefix);
321
+ }
322
+ }
323
+
324
+ private calcPosition({ y, height }: { y: number; height: number }): number {
325
+ // check if it's outside of the bounds
326
+ const first = this.offsets[0];
327
+ if (y < first.y - height * first.view) return -1;
328
+
329
+ const last = this.offsets[this.offsets.length - 1];
330
+ if (y > last.y - height * last.view) return 2;
331
+
179
332
  // find the matching offset
180
333
  // rolling window
181
334
  for (let i = 1; i < this.offsets.length; i++) {
182
335
  const start = this.offsets[i - 1];
183
336
  const end = this.offsets[i];
184
337
 
185
- const startY = start.y + height * start.view;
186
- const endY = end.y + height * end.view;
187
-
188
- const dif = endY - startY;
189
- const x = 1 - (endY - y) / dif;
338
+ const startY = start.y - height * start.view;
339
+ const endY = end.y - height * end.view;
190
340
 
191
- for (const timeline of this.timelines) {
192
- // calc pos range
193
- const pos =
194
- start.position + (end.position - start.position) * x;
341
+ if (y >= startY && y < endY) {
342
+ const dif = endY - startY;
343
+ const x = 1 - (endY - y) / dif;
195
344
 
196
- timeline.seek(pos);
345
+ return start.position + (end.position - start.position) * x;
197
346
  }
198
347
  }
348
+
349
+ return -1;
199
350
  }
200
351
  }
201
352
 
@@ -239,7 +390,7 @@ function parseTrigger(
239
390
  target: element,
240
391
  offset: parseOffset(offset),
241
392
  view: parseOffset(view),
242
- position: position ?? (i == 0 ? 0 : 1),
393
+ position,
243
394
  };
244
395
  }
245
396
 
@@ -261,7 +412,7 @@ function parseOffset(val: OffsetValue): number {
261
412
  throw new Error('unknown view value ' + val);
262
413
  }
263
414
 
264
- if (typeof val !== 'number' || val < 0 || val > 1) {
415
+ if (typeof val !== 'number') {
265
416
  throw new Error(
266
417
  'view expecting to be a top/center/bottom or a percent value',
267
418
  );
@@ -10,6 +10,7 @@ export default class ScrollEvent {
10
10
  this._listeners = new Set();
11
11
 
12
12
  window.addEventListener('scroll', e => this._onScroll(e));
13
+ window.addEventListener('resize', e => this._onScroll(e));
13
14
  }
14
15
 
15
16
  static global() {
@@ -1,5 +1,8 @@
1
+ import type { Position, ScrollTrigger } from './Scroll.js';
1
2
  import Scroll from './public.js';
2
3
 
4
+ export { Scroll, ScrollTrigger, Position };
5
+
3
6
  /**
4
7
  * Create a scroll animation
5
8
  */