chnobli 0.1.8 → 0.1.9

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 (202) hide show
  1. package/package.json +9 -5
  2. package/src/animation/Animation.ts +2 -2
  3. package/src/animation/public.ts +39 -5
  4. package/src/chnobli.ts +15 -11
  5. package/src/property/Property.ts +2 -0
  6. package/src/property/StyleProperty.ts +2 -2
  7. package/src/scroll/Scroll.ts +172 -88
  8. package/src/scroll/index.ts +8 -0
  9. package/src/scroll/public.ts +23 -12
  10. package/src/stagger/stagger.ts +28 -14
  11. package/src/target/ObjectTarget.ts +124 -0
  12. package/src/target/Target.ts +13 -0
  13. package/src/tests/properties.test.ts +51 -1
  14. package/src/timeline/Nested.ts +1 -1
  15. package/src/timeline/{TimeLine.ts → Timeline.ts} +21 -1
  16. package/src/timeline/public.ts +168 -47
  17. package/src/timing/Timing.ts +37 -3
  18. package/src/utils/internal.ts +6 -3
  19. package/src/utils/utils.ts +16 -7
  20. package/src/values/StyleValue.ts +13 -1
  21. package/tsconfig.json +0 -1
  22. package/.editorconfig +0 -11
  23. package/.github/workflows/ci.yaml +0 -34
  24. package/.prettierignore +0 -4
  25. package/.prettierrc +0 -6
  26. package/.vscode/settings.json +0 -4
  27. package/LICENSE.md +0 -21
  28. package/README.md +0 -5
  29. package/auto-docs/easing.js.html +0 -342
  30. package/auto-docs/fonts/OpenSans-Bold-webfont.eot +0 -0
  31. package/auto-docs/fonts/OpenSans-Bold-webfont.svg +0 -1830
  32. package/auto-docs/fonts/OpenSans-Bold-webfont.woff +0 -0
  33. package/auto-docs/fonts/OpenSans-BoldItalic-webfont.eot +0 -0
  34. package/auto-docs/fonts/OpenSans-BoldItalic-webfont.svg +0 -1830
  35. package/auto-docs/fonts/OpenSans-BoldItalic-webfont.woff +0 -0
  36. package/auto-docs/fonts/OpenSans-Italic-webfont.eot +0 -0
  37. package/auto-docs/fonts/OpenSans-Italic-webfont.svg +0 -1830
  38. package/auto-docs/fonts/OpenSans-Italic-webfont.woff +0 -0
  39. package/auto-docs/fonts/OpenSans-Light-webfont.eot +0 -0
  40. package/auto-docs/fonts/OpenSans-Light-webfont.svg +0 -1831
  41. package/auto-docs/fonts/OpenSans-Light-webfont.woff +0 -0
  42. package/auto-docs/fonts/OpenSans-LightItalic-webfont.eot +0 -0
  43. package/auto-docs/fonts/OpenSans-LightItalic-webfont.svg +0 -1835
  44. package/auto-docs/fonts/OpenSans-LightItalic-webfont.woff +0 -0
  45. package/auto-docs/fonts/OpenSans-Regular-webfont.eot +0 -0
  46. package/auto-docs/fonts/OpenSans-Regular-webfont.svg +0 -1831
  47. package/auto-docs/fonts/OpenSans-Regular-webfont.woff +0 -0
  48. package/auto-docs/global.html +0 -4810
  49. package/auto-docs/index.html +0 -65
  50. package/auto-docs/scripts/linenumber.js +0 -25
  51. package/auto-docs/scripts/prettify/Apache-License-2.0.txt +0 -202
  52. package/auto-docs/scripts/prettify/lang-css.js +0 -2
  53. package/auto-docs/scripts/prettify/prettify.js +0 -28
  54. package/auto-docs/styles/jsdoc-default.css +0 -358
  55. package/auto-docs/styles/prettify-jsdoc.css +0 -111
  56. package/auto-docs/styles/prettify-tomorrow.css +0 -132
  57. package/dist/animation/Animation.d.ts +0 -36
  58. package/dist/animation/Animation.d.ts.map +0 -1
  59. package/dist/animation/Animation.js +0 -230
  60. package/dist/animation/Animation.js.map +0 -1
  61. package/dist/animation/public.d.ts +0 -58
  62. package/dist/animation/public.d.ts.map +0 -1
  63. package/dist/animation/public.js +0 -107
  64. package/dist/animation/public.js.map +0 -1
  65. package/dist/chnobli.d.ts +0 -16
  66. package/dist/chnobli.d.ts.map +0 -1
  67. package/dist/chnobli.js +0 -63
  68. package/dist/chnobli.js.map +0 -1
  69. package/dist/property/BasicProperty.d.ts +0 -38
  70. package/dist/property/BasicProperty.d.ts.map +0 -1
  71. package/dist/property/BasicProperty.js +0 -72
  72. package/dist/property/BasicProperty.js.map +0 -1
  73. package/dist/property/ClassProperty.d.ts +0 -32
  74. package/dist/property/ClassProperty.d.ts.map +0 -1
  75. package/dist/property/ClassProperty.js +0 -108
  76. package/dist/property/ClassProperty.js.map +0 -1
  77. package/dist/property/Property.d.ts +0 -13
  78. package/dist/property/Property.d.ts.map +0 -1
  79. package/dist/property/Property.js +0 -20
  80. package/dist/property/Property.js.map +0 -1
  81. package/dist/property/StyleProperty.d.ts +0 -25
  82. package/dist/property/StyleProperty.d.ts.map +0 -1
  83. package/dist/property/StyleProperty.js +0 -221
  84. package/dist/property/StyleProperty.js.map +0 -1
  85. package/dist/property/TransformProperty.d.ts +0 -15
  86. package/dist/property/TransformProperty.d.ts.map +0 -1
  87. package/dist/property/TransformProperty.js +0 -43
  88. package/dist/property/TransformProperty.js.map +0 -1
  89. package/dist/property/TransformXYProperty.d.ts +0 -28
  90. package/dist/property/TransformXYProperty.d.ts.map +0 -1
  91. package/dist/property/TransformXYProperty.js +0 -65
  92. package/dist/property/TransformXYProperty.js.map +0 -1
  93. package/dist/responsive/ResponsiveEvent.d.ts +0 -17
  94. package/dist/responsive/ResponsiveEvent.d.ts.map +0 -1
  95. package/dist/responsive/ResponsiveEvent.js +0 -45
  96. package/dist/responsive/ResponsiveEvent.js.map +0 -1
  97. package/dist/responsive/TestEvent.d.ts +0 -11
  98. package/dist/responsive/TestEvent.d.ts.map +0 -1
  99. package/dist/responsive/TestEvent.js +0 -26
  100. package/dist/responsive/TestEvent.js.map +0 -1
  101. package/dist/scroll/Scroll.d.ts +0 -27
  102. package/dist/scroll/Scroll.d.ts.map +0 -1
  103. package/dist/scroll/Scroll.js +0 -132
  104. package/dist/scroll/Scroll.js.map +0 -1
  105. package/dist/scroll/ScrollEvent.d.ts +0 -17
  106. package/dist/scroll/ScrollEvent.d.ts.map +0 -1
  107. package/dist/scroll/ScrollEvent.js +0 -39
  108. package/dist/scroll/ScrollEvent.js.map +0 -1
  109. package/dist/scroll/public.d.ts +0 -7
  110. package/dist/scroll/public.d.ts.map +0 -1
  111. package/dist/scroll/public.js +0 -17
  112. package/dist/scroll/public.js.map +0 -1
  113. package/dist/stagger/stagger.d.ts +0 -19
  114. package/dist/stagger/stagger.d.ts.map +0 -1
  115. package/dist/stagger/stagger.js +0 -41
  116. package/dist/stagger/stagger.js.map +0 -1
  117. package/dist/target/BaseTarget.old.d.ts +0 -33
  118. package/dist/target/BaseTarget.old.d.ts.map +0 -1
  119. package/dist/target/BaseTarget.old.js +0 -73
  120. package/dist/target/BaseTarget.old.js.map +0 -1
  121. package/dist/target/DomTarget.d.ts +0 -41
  122. package/dist/target/DomTarget.d.ts.map +0 -1
  123. package/dist/target/DomTarget.js +0 -230
  124. package/dist/target/DomTarget.js.map +0 -1
  125. package/dist/target/Target.d.ts +0 -22
  126. package/dist/target/Target.d.ts.map +0 -1
  127. package/dist/target/Target.js +0 -21
  128. package/dist/target/Target.js.map +0 -1
  129. package/dist/target/TestDomNode.d.ts +0 -14
  130. package/dist/target/TestDomNode.d.ts.map +0 -1
  131. package/dist/target/TestDomNode.js +0 -55
  132. package/dist/target/TestDomNode.js.map +0 -1
  133. package/dist/timeline/Nested.d.ts +0 -30
  134. package/dist/timeline/Nested.d.ts.map +0 -1
  135. package/dist/timeline/Nested.js +0 -51
  136. package/dist/timeline/Nested.js.map +0 -1
  137. package/dist/timeline/TimeLine.d.ts +0 -32
  138. package/dist/timeline/TimeLine.d.ts.map +0 -1
  139. package/dist/timeline/TimeLine.js +0 -288
  140. package/dist/timeline/TimeLine.js.map +0 -1
  141. package/dist/timeline/public.d.ts +0 -135
  142. package/dist/timeline/public.d.ts.map +0 -1
  143. package/dist/timeline/public.js +0 -316
  144. package/dist/timeline/public.js.map +0 -1
  145. package/dist/timing/AnimationFrameTicker.d.ts +0 -32
  146. package/dist/timing/AnimationFrameTicker.d.ts.map +0 -1
  147. package/dist/timing/AnimationFrameTicker.js +0 -134
  148. package/dist/timing/AnimationFrameTicker.js.map +0 -1
  149. package/dist/timing/Ease.d.ts +0 -6
  150. package/dist/timing/Ease.d.ts.map +0 -1
  151. package/dist/timing/Ease.js +0 -15
  152. package/dist/timing/Ease.js.map +0 -1
  153. package/dist/timing/TestTicker.d.ts +0 -19
  154. package/dist/timing/TestTicker.d.ts.map +0 -1
  155. package/dist/timing/TestTicker.js +0 -81
  156. package/dist/timing/TestTicker.js.map +0 -1
  157. package/dist/timing/Ticker.d.ts +0 -14
  158. package/dist/timing/Ticker.d.ts.map +0 -1
  159. package/dist/timing/Ticker.js +0 -2
  160. package/dist/timing/Ticker.js.map +0 -1
  161. package/dist/timing/Timing.d.ts +0 -62
  162. package/dist/timing/Timing.d.ts.map +0 -1
  163. package/dist/timing/Timing.js +0 -257
  164. package/dist/timing/Timing.js.map +0 -1
  165. package/dist/timing/easing.d.ts +0 -158
  166. package/dist/timing/easing.d.ts.map +0 -1
  167. package/dist/timing/easing.js +0 -273
  168. package/dist/timing/easing.js.map +0 -1
  169. package/dist/utils/Events.d.ts +0 -9
  170. package/dist/utils/Events.d.ts.map +0 -1
  171. package/dist/utils/Events.js +0 -35
  172. package/dist/utils/Events.js.map +0 -1
  173. package/dist/utils/internal.d.ts +0 -2
  174. package/dist/utils/internal.d.ts.map +0 -1
  175. package/dist/utils/internal.js +0 -6
  176. package/dist/utils/internal.js.map +0 -1
  177. package/dist/utils/motionpath.d.ts +0 -16
  178. package/dist/utils/motionpath.d.ts.map +0 -1
  179. package/dist/utils/motionpath.js +0 -41
  180. package/dist/utils/motionpath.js.map +0 -1
  181. package/dist/utils/utils.d.ts +0 -43
  182. package/dist/utils/utils.d.ts.map +0 -1
  183. package/dist/utils/utils.js +0 -93
  184. package/dist/utils/utils.js.map +0 -1
  185. package/dist/values/ColorValue.d.ts +0 -12
  186. package/dist/values/ColorValue.d.ts.map +0 -1
  187. package/dist/values/ColorValue.js +0 -133
  188. package/dist/values/ColorValue.js.map +0 -1
  189. package/dist/values/StyleValue.d.ts +0 -40
  190. package/dist/values/StyleValue.d.ts.map +0 -1
  191. package/dist/values/StyleValue.js +0 -149
  192. package/dist/values/StyleValue.js.map +0 -1
  193. package/dist/values/Value.d.ts +0 -13
  194. package/dist/values/Value.d.ts.map +0 -1
  195. package/dist/values/Value.js +0 -38
  196. package/dist/values/Value.js.map +0 -1
  197. package/dist/values/defaultcolors.d.ts +0 -2
  198. package/dist/values/defaultcolors.d.ts.map +0 -1
  199. package/dist/values/defaultcolors.js +0 -149
  200. package/dist/values/defaultcolors.js.map +0 -1
  201. package/docs/INDEX.md +0 -15
  202. package/jsr.json +0 -9
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "chnobli",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "author": "Sören Meier <info@soerenmeier.ch>",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "docs": "jsdoc -c jsdoc.conf.json",
8
8
  "check": "tsc",
9
9
  "lint": "eslint ./src",
10
- "test": "node --expose-gc ./node_modules/.bin/vitest run",
11
- "test:watch": "node --expose-gc ./node_modules/.bin/vitest",
10
+ "test": "node --expose-gc ../node_modules/.bin/vitest run",
11
+ "test:watch": "node --expose-gc ../node_modules/.bin/vitest",
12
12
  "build": "tsc -p tsconfig.build.json",
13
- "watch": "tsc -w"
13
+ "watch": "tsc -w -p tsconfig.build.json"
14
14
  },
15
15
  "repository": {
16
16
  "type": "git",
@@ -26,6 +26,10 @@
26
26
  "import": "./dist/utils/utils.js",
27
27
  "types": "./dist/utils/utils.d.ts"
28
28
  },
29
+ "./scroll": {
30
+ "import": "./dist/scroll/index.js",
31
+ "types": "./dist/scroll/index.d.ts"
32
+ },
29
33
  ".": {
30
34
  "import": "./dist/chnobli.js",
31
35
  "types": "./dist/chnobli.d.ts"
@@ -41,6 +45,6 @@
41
45
  },
42
46
  "dependencies": {
43
47
  "bezier-easing": "^2.1.0",
44
- "fire": "npm:fire-lib-js@^0.3.0-alpha.11"
48
+ "fire": "npm:fire-lib-js@^0.3.0"
45
49
  }
46
50
  }
@@ -116,6 +116,7 @@ class PropertyAnimation<V> {
116
116
  private valueFn: ((pos: number) => ParseableValue) | null;
117
117
 
118
118
  private iniResponsive: any;
119
+ // todo i don't think the types match here?
119
120
  private iniFrom: V | null;
120
121
  private iniTo: V | null;
121
122
 
@@ -166,8 +167,7 @@ class PropertyAnimation<V> {
166
167
 
167
168
  // init via responsive fn
168
169
  if (this.iniResponsive) {
169
- // todo this access to target can't be
170
- const value = this.iniResponsive((target as any).target);
170
+ const value = this.iniResponsive(target.inner());
171
171
 
172
172
  if (typeof value === 'object') {
173
173
  if ('from' in value) from = this.prop.parseValue(value.from);
@@ -1,6 +1,20 @@
1
1
  import { takeProp } from '../utils/internal.js';
2
2
  import Timeline from '../timeline/public.js';
3
- import { staggerMap } from '../stagger/stagger.js';
3
+ import Stagger, { staggerMap } from '../stagger/stagger.js';
4
+ import { Targets } from '../chnobli.js';
5
+
6
+ export type AnimationProps = {
7
+ autoplay?: boolean;
8
+ delay?: number | string | Stagger<number | string>;
9
+
10
+ ease?: (t: number) => number;
11
+
12
+ onStart?: () => void;
13
+ onEnd?: () => void;
14
+
15
+ // other properties
16
+ [key: string]: any;
17
+ };
4
18
 
5
19
  /**
6
20
  * The animation consist of a timeline with just one animation
@@ -12,16 +26,36 @@ import { staggerMap } from '../stagger/stagger.js';
12
26
  export default class PublicAnimation {
13
27
  private _tl: Timeline;
14
28
 
15
- constructor(targets: any, props: Record<string, any> = {}) {
29
+ constructor(targets: Targets, props: AnimationProps = {}) {
16
30
  const autoplay = parseAutoplay(takeProp(props, 'autoplay', true));
17
- const delay = takeProp(props, 'delay', 0);
31
+ const delay = takeProp<number>(props, 'delay', 0);
18
32
 
19
33
  // we don't wan't the ease and duration on the timeline
20
- const ease = takeProp(props, 'ease', null);
21
- const duration = takeProp(props, 'duration', null);
34
+ const ease = takeProp<AnimationProps['ease']>(props, 'ease', undefined);
35
+ const duration = takeProp<number | undefined>(
36
+ props,
37
+ 'duration',
38
+ undefined,
39
+ );
22
40
 
23
41
  this._tl = new Timeline(props);
24
42
 
43
+ // events
44
+ const onStart = takeProp<AnimationProps['onStart']>(
45
+ props,
46
+ 'onStart',
47
+ undefined,
48
+ );
49
+ if (onStart) this._tl.on('start', onStart);
50
+
51
+ // events
52
+ const onEnd = takeProp<AnimationProps['onEnd']>(
53
+ props,
54
+ 'onEnd',
55
+ undefined,
56
+ );
57
+ if (onEnd) this._tl.on('end', onEnd);
58
+
25
59
  props.ease = ease;
26
60
  props.duration = duration;
27
61
 
package/src/chnobli.ts CHANGED
@@ -1,9 +1,17 @@
1
- import Animation from './animation/public.js';
1
+ import Animation, { AnimationProps } from './animation/public.js';
2
2
  import Timeline from './timeline/public.js';
3
- import Scroll from './scroll/public.js';
4
- import Stagger from './stagger/stagger.js';
3
+ import Stagger, { type StaggerValue } from './stagger/stagger.js';
4
+ import type { Targets, AnimationTarget } from './target/Target.js';
5
5
 
6
- export type { Animation, Timeline, Stagger, Scroll };
6
+ export type {
7
+ Animation,
8
+ Timeline,
9
+ Stagger,
10
+ Targets,
11
+ AnimationTarget,
12
+ StaggerValue,
13
+ AnimationProps,
14
+ };
7
15
 
8
16
  // todo maybe add, to, from and fromTo to the animate function
9
17
 
@@ -14,8 +22,8 @@ export type { Animation, Timeline, Stagger, Scroll };
14
22
  *
15
23
  */
16
24
  export function animate(
17
- targets: any,
18
- props: Record<string, any> = {},
25
+ targets: Targets,
26
+ props: AnimationProps = {},
19
27
  ): Animation {
20
28
  return new Animation(targets, props);
21
29
  }
@@ -24,14 +32,10 @@ export function timeline(props: Record<string, any> = {}): Timeline {
24
32
  return new Timeline(props);
25
33
  }
26
34
 
27
- export function stagger(value: any): Stagger {
35
+ export function stagger<O>(value: StaggerValue<O>): Stagger<O> {
28
36
  return new Stagger(value);
29
37
  }
30
38
 
31
- export function scroll(props: Record<string, any> = {}): Scroll {
32
- return new Scroll(props);
33
- }
34
-
35
39
  /*
36
40
 
37
41
  animate(target, {
@@ -20,6 +20,8 @@ export default interface Property<V, I = V> {
20
20
  }
21
21
 
22
22
  export function newProperty(prop: string, targetType = ''): Property<any> {
23
+ if (targetType === 'object') return new StyleProperty(prop, false);
24
+
23
25
  if (targetType !== 'dom')
24
26
  throw new Error('only dom is supported as target');
25
27
 
@@ -41,13 +41,13 @@ export default class StyleProperty
41
41
 
42
42
  private _defaultValue: StyleValue | null;
43
43
 
44
- constructor(name: string) {
44
+ constructor(name: string, useDefaults: boolean = true) {
45
45
  this.name = name;
46
46
 
47
47
  this.from = null;
48
48
  this.to = null;
49
49
 
50
- const def = STYLE_PROPS[name];
50
+ const def = useDefaults ? STYLE_PROPS[name] : undefined;
51
51
  if (Array.isArray(def)) {
52
52
  this._defaultValue = new StyleValue([new Value(def[0], def[1])]);
53
53
  this.unit = def[1];
@@ -1,9 +1,29 @@
1
- import PublicTimeline from '../timeline/public.js';
2
- import { takeProp } from '../utils/internal.js';
1
+ import PublicTimeline, { Offset } from '../timeline/public.js';
3
2
  import { pageOffset } from '../utils/utils.js';
4
3
  import ScrollEvent from './ScrollEvent.js';
5
4
 
6
5
  /*
6
+ run timelines based on the scroll position
7
+
8
+ scroll allows to specify a start and end trigger
9
+ which then makes sure the timeline is always in sync with
10
+ the scroll position
11
+
12
+ {
13
+ start: myDiv,
14
+ // when the top of myDiv is at the top of the viewport
15
+ end: {
16
+ target: myDiv,
17
+ offset: 'bottom',
18
+ view: 'bottom'
19
+ }
20
+ // when the bottom of myDiv is at the bottom of the viewport
21
+ }
22
+
23
+
24
+
25
+
26
+
7
27
  run animation when in view (start stop resume when different events happen)
8
28
 
9
29
 
@@ -24,57 +44,76 @@ scroll pin (once in trigger zone, elements keeps it position relative to start o
24
44
  parallax
25
45
  */
26
46
 
27
- type StartEndOffset = {
47
+ export type ScrollTrigger =
48
+ | {
49
+ target: HTMLElement;
50
+ offset?: OffsetValue;
51
+ view?: OffsetValue;
52
+ }
53
+ | HTMLElement;
54
+
55
+ export type OffsetValue = 'top' | 'center' | 'bottom' | number;
56
+
57
+ export type ParsedScrollTrigger = {
28
58
  target: HTMLElement;
29
59
  offset: number;
30
- };
31
-
32
- export type Start = {
33
- y: number;
34
60
  view: number;
61
+ position: Position;
35
62
  };
36
63
 
37
- export type End = {
64
+ export type ScrollOffset = {
65
+ // the offset in pixels
38
66
  y: number;
67
+ // the offset in percentage (0-1)
39
68
  view: number;
69
+ // position
70
+ position: number;
40
71
  };
41
72
 
42
- export default class Scroll {
43
- private _start: StartEndOffset;
44
- private _end: StartEndOffset | null;
45
- private _globalEvent: ScrollEvent;
73
+ export type Position = number | string;
46
74
 
47
- start: Start;
48
- end: End;
75
+ export default class ScrollTimeline {
76
+ private _initialized: boolean;
77
+ private _globalEvent: ScrollEvent;
78
+ private _rmEvent: () => void;
49
79
 
80
+ private _triggers: ParsedScrollTrigger[];
50
81
  private timelines: PublicTimeline[];
51
- private _rmEvent: () => void;
52
- private _initialized: boolean;
82
+ offsets: ScrollOffset[];
53
83
 
54
- constructor(props = {}) {
55
- // { target, offset }
56
- this._start = parseStart(takeProp(props, 'start', null));
57
- // { target, offset }
58
- this._end = parseEnd(takeProp(props, 'end', null));
84
+ constructor() {
85
+ this._initialized = false;
59
86
  this._globalEvent = ScrollEvent.global();
87
+ this._rmEvent = this._globalEvent.add(y => this._onScroll(y)).remove;
60
88
 
61
- this.start = {
62
- // px
63
- y: 0,
64
- // percentage
65
- view: parseOffset(takeProp(props, 'startView', 'top')),
66
- };
67
- this.end = {
68
- // px
69
- y: 0,
70
- // percentage
71
- view: parseOffset(takeProp(props, 'endView', 'bottom')),
72
- };
73
-
89
+ this._triggers = [];
74
90
  this.timelines = [];
91
+ this.offsets = [];
92
+
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');
104
+ }
75
105
 
76
- this._rmEvent = this._globalEvent.add(y => this._onScroll(y)).remove;
77
- this._initialized = false;
106
+ /**
107
+ * Add a trigger to the timeline
108
+ *
109
+ * Providing an offset at which point the trigger should end
110
+ *
111
+ * If it is the first trigger it is not allowed to be set?
112
+ */
113
+ add(trigger: ScrollTrigger, position?: Position) {
114
+ this._triggers.push(
115
+ parseTrigger(trigger, position, this._triggers.length),
116
+ );
78
117
  }
79
118
 
80
119
  addTimeline(timeline: PublicTimeline) {
@@ -82,77 +121,113 @@ export default class Scroll {
82
121
  }
83
122
 
84
123
  init() {
85
- const startOffset = pageOffset(this._start.target);
86
- this.start.y =
87
- startOffset.top + startOffset.height * this._start.offset;
88
-
89
- if (this._end) {
90
- const offset = pageOffset(this._end.target);
91
- this.end.y = offset.top + offset.height * this._end.offset;
92
- } else {
93
- this.end.y = this.start.y + pageOffset(this._start.target).height;
124
+ // todo we need to calculate the position for each timeline
125
+ //
126
+ // calculate the positions and offsets
127
+ // if we are missing one extend them
128
+
129
+ let previousY = -1;
130
+
131
+ this.offsets = this._triggers.map(t => {
132
+ const offset = pageOffset(t.target);
133
+
134
+ const y = offset.top + offset.height * t.offset;
135
+
136
+ if (y < previousY) throw new Error('offsets are not in order');
137
+
138
+ let position;
139
+ if (typeof t.position === 'string') {
140
+ if (this.timelines.length !== 1)
141
+ throw new Error(
142
+ 'labels can only be used with one timeline',
143
+ );
144
+
145
+ position = this.timelines[0].labelPosition(t.position);
146
+ } else if (t.position >= 0 || t.position <= 1) {
147
+ position = t.position;
148
+ } else {
149
+ throw new Error('position should be between 0 and 1');
150
+ }
151
+
152
+ return {
153
+ y,
154
+ view: t.view,
155
+ position,
156
+ };
157
+ });
158
+
159
+ if (this.offsets.length < 1)
160
+ throw new Error('scroll timeline needs at least one trigger');
161
+
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
+ });
94
170
  }
95
171
  }
96
172
 
97
- _onScroll({ y, height }: { y: number; height: number }) {
173
+ private _onScroll({ y, height }: { y: number; height: number }) {
98
174
  if (!this._initialized) {
99
175
  this.init();
100
176
  this._initialized = true;
101
177
  }
102
178
 
103
- const start = this.start.y + height * this.start.view;
104
- const end = this.end.y + height * this.end.view;
179
+ // find the matching offset
180
+ // rolling window
181
+ for (let i = 1; i < this.offsets.length; i++) {
182
+ const start = this.offsets[i - 1];
183
+ const end = this.offsets[i];
105
184
 
106
- const dif = end - start;
107
- const x = 1 - (end - y) / dif;
185
+ const startY = start.y + height * start.view;
186
+ const endY = end.y + height * end.view;
108
187
 
109
- for (const timeline of this.timelines) {
110
- timeline.seek(x);
111
- }
112
- }
113
- }
188
+ const dif = endY - startY;
189
+ const x = 1 - (endY - y) / dif;
114
190
 
115
- function parseStart(val: any): StartEndOffset {
116
- // might be an object { target, offset }
117
- if (!val) {
118
- throw new Error(
119
- 'unknown start property use an html element or an object',
120
- );
121
- }
122
-
123
- let element = null;
124
- let offset = 'top';
191
+ for (const timeline of this.timelines) {
192
+ // calc pos range
193
+ const pos =
194
+ start.position + (end.position - start.position) * x;
125
195
 
126
- if (typeof val === 'object') {
127
- if (val instanceof HTMLElement) element = val;
128
- else if ('target' in val) {
129
- element = val.target;
130
- if (typeof val.offset !== 'undefined') offset = val.offset;
131
- } else {
132
- throw new Error('start unknown ' + val);
196
+ timeline.seek(pos);
197
+ }
133
198
  }
134
- } else {
135
- throw new Error('unknown start val');
136
199
  }
137
-
138
- return {
139
- target: element,
140
- offset: parseOffset(offset),
141
- };
142
200
  }
143
201
 
144
- function parseEnd(val: any): StartEndOffset | null {
202
+ /**
203
+ * Parse the start property
204
+ *
205
+ * can be an HTMLElement or an object { target, offset }
206
+ *
207
+ * the default offset is top
208
+ * the default view is top
209
+ */
210
+ function parseTrigger(
211
+ val: ScrollTrigger,
212
+ position: Position | undefined,
213
+ i: number,
214
+ ): ParsedScrollTrigger {
145
215
  // might be an object { target, offset }
146
- if (!val) return null;
216
+ if (!val) {
217
+ throw new Error('unknown property use an html element or an object');
218
+ }
147
219
 
148
220
  let element = null;
149
- let offset = 'top';
221
+ let offset: OffsetValue = 'top';
222
+ let view: OffsetValue = i == 0 ? 'top' : 'bottom';
150
223
 
151
224
  if (typeof val === 'object') {
152
- if (val instanceof HTMLElement) element = val;
153
- else if ('target' in val) {
225
+ if (val instanceof HTMLElement) {
226
+ element = val;
227
+ } else if ('target' in val) {
154
228
  element = val.target;
155
229
  if (typeof val.offset !== 'undefined') offset = val.offset;
230
+ if (typeof val.view !== 'undefined') view = val.view;
156
231
  } else {
157
232
  throw new Error('start unknown ' + val);
158
233
  }
@@ -163,21 +238,30 @@ function parseEnd(val: any): StartEndOffset | null {
163
238
  return {
164
239
  target: element,
165
240
  offset: parseOffset(offset),
241
+ view: parseOffset(view),
242
+ position: position ?? (i == 0 ? 0 : 1),
166
243
  };
167
244
  }
168
245
 
169
- function parseOffset(val: any): number {
246
+ /**
247
+ * Parse the offset value
248
+ *
249
+ * can be a string (top, center, bottom) or a number (0-1)
250
+ *
251
+ * 0 = top
252
+ * 0.5 = center
253
+ * 1 = bottom
254
+ */
255
+ function parseOffset(val: OffsetValue): number {
170
256
  if (typeof val === 'string') {
171
257
  if (val === 'top') return 0;
172
-
173
258
  if (val === 'center') return 0.5;
174
-
175
259
  if (val === 'bottom') return 1;
176
260
 
177
261
  throw new Error('unknown view value ' + val);
178
262
  }
179
263
 
180
- if (typeof val !== 'number') {
264
+ if (typeof val !== 'number' || val < 0 || val > 1) {
181
265
  throw new Error(
182
266
  'view expecting to be a top/center/bottom or a percent value',
183
267
  );
@@ -0,0 +1,8 @@
1
+ import Scroll from './public.js';
2
+
3
+ /**
4
+ * Create a scroll animation
5
+ */
6
+ export function scroll(): Scroll {
7
+ return new Scroll();
8
+ }
@@ -1,20 +1,31 @@
1
- import PublicTimeline from '../timeline/public.js';
2
- import Scroll from './Scroll.js';
1
+ import { Timeline } from '../chnobli.js';
2
+ // import Scroll from './Scroll.js';
3
+ import ScrollTimeline, { Position, ScrollTrigger } from './Scroll.js';
3
4
 
4
- export default class PublicScroll {
5
- private _inner: Scroll;
5
+ export default class Scroll {
6
+ private _inner: ScrollTimeline;
6
7
 
7
- /*
8
- {
9
- start: el | px
10
- startView: 'top'
8
+ constructor() {
9
+ this._inner = new ScrollTimeline();
11
10
  }
12
- */
13
- constructor(props: Record<string, any> = {}) {
14
- this._inner = new Scroll(props);
11
+
12
+ /**
13
+ * Add a trigger to the timeline
14
+ *
15
+ * Providing an offset at which point the trigger should end
16
+ */
17
+ add(trigger: ScrollTrigger, position?: Position): this {
18
+ this._inner.add(trigger, position);
19
+
20
+ return this;
15
21
  }
16
22
 
17
- add(timeline: PublicTimeline) {
23
+ /**
24
+ * Add a timeline to the scroll
25
+ */
26
+ addTimeline(timeline: Timeline): this {
18
27
  this._inner.addTimeline(timeline);
28
+
29
+ return this;
19
30
  }
20
31
  }
@@ -3,34 +3,48 @@
3
3
  * allowing to easely offset each target by a few pixels
4
4
  */
5
5
 
6
- function isStagger(value: any) {
6
+ function isStagger<O>(value: any): value is Stagger<O> {
7
+ const v = value as any;
8
+
7
9
  return (
8
- typeof value === 'object' &&
9
- value !== null &&
10
- typeof value.__isStagger__ === 'function'
10
+ typeof v === 'object' &&
11
+ v !== null &&
12
+ typeof v.__isStagger__ === 'function'
11
13
  );
12
14
  }
13
15
 
14
- export function callStagger(value: any, i: number, l: any = null) {
15
- if (isStagger(value)) return value.call(i, l);
16
+ export function callStagger<O>(
17
+ value: O | Stagger<O>,
18
+ i: number,
19
+ length?: number,
20
+ ): O {
21
+ if (isStagger(value)) return value.call(i, length);
16
22
 
17
23
  return value;
18
24
  }
19
25
 
20
- export function staggerMap(value: any, fn: (v: any) => any) {
21
- if (isStagger(value))
22
- return new Stagger((...args: any[]) => fn(value.call(...args)));
26
+ export function staggerMap<O, NO>(
27
+ value: O | Stagger<O>,
28
+ fn: (val: O) => NO,
29
+ ): NO | Stagger<NO> {
30
+ if (isStagger(value)) {
31
+ return new Stagger((i: number, length?: number) =>
32
+ fn(value.call(i, length)),
33
+ );
34
+ }
23
35
 
24
36
  return fn(value);
25
37
  }
26
38
 
27
- export default class Stagger {
28
- private fn: (...args: any[]) => any;
39
+ export type StaggerValue<O> = (i: number, length?: number) => O;
40
+
41
+ export default class Stagger<O> {
42
+ private fn: StaggerValue<O>;
29
43
 
30
44
  /**
31
45
  * @ignore
32
46
  */
33
- constructor(value: any) {
47
+ constructor(value: StaggerValue<O>) {
34
48
  if (typeof value === 'function') {
35
49
  this.fn = value;
36
50
  return;
@@ -40,8 +54,8 @@ export default class Stagger {
40
54
  throw new Error('unknown stagger value ' + value);
41
55
  }
42
56
 
43
- call(...args: any[]): any {
44
- return this.fn(...args);
57
+ call(i: number, length?: number): O {
58
+ return this.fn(i, length);
45
59
  }
46
60
 
47
61
  /**