@egjs/flicking-plugins 4.2.2 → 4.4.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/src/Sync.ts CHANGED
@@ -1,14 +1,25 @@
1
- import Flicking, { EVENTS, Panel, Plugin } from "@egjs/flicking";
1
+ import Flicking, { clamp, EVENTS } from "@egjs/flicking";
2
+ import type { MoveEndEvent, MoveEvent, MoveStartEvent, Plugin, WillChangeEvent, SelectEvent } from "@egjs/flicking";
2
3
 
3
4
  import { SYNC } from "./const";
4
5
  import { addClass, removeClass } from "./utils";
5
6
 
6
- interface SyncOptions {
7
- type: "camera" | "index";
7
+ /**
8
+ * @property {string} [type="camera"] Types of methods to synchronize between Flickings. "camera" will sync by camera position, and "index" will sync by panel index
9
+ * @property {SychronizableFlickingOptions} [synchronizedFlickingOptions=[]] Detailed options for syncing Flickings.
10
+ */
11
+ export interface SyncOptions {
12
+ type: typeof SYNC.TYPE.CAMERA | typeof SYNC.TYPE.INDEX;
8
13
  synchronizedFlickingOptions: SychronizableFlickingOptions[];
9
14
  }
10
15
 
11
- interface SychronizableFlickingOptions {
16
+ /**
17
+ * @property {Flicking} flicking An instance of Flicking to sync
18
+ * @property {boolean} [isClickable=false] By enabling this option, clicking the given Flicking's panel will change the given & other Flicking's index
19
+ * @property {boolean} [isSlidable=false] By enabling this option, the given Flicking's scroll with mouse/touch input will change other Flicking's index. Only available for the index type
20
+ * @property {string | undefined} [activeClass=undefined] An extra class for the panels when selected
21
+ */
22
+ export interface SychronizableFlickingOptions {
12
23
  flicking: Flicking;
13
24
  isClickable?: boolean;
14
25
  isSlidable?: boolean;
@@ -32,15 +43,11 @@ class Sync implements Plugin {
32
43
  public get synchronizedFlickingOptions() { return this._synchronizedFlickingOptions; }
33
44
 
34
45
  public set type(val: SyncOptions["type"]) {
35
- this._preventEvent(() => {
36
- this._type = val;
37
- });
46
+ this._type = val;
38
47
  }
39
48
 
40
49
  public set synchronizedFlickingOptions(val: SyncOptions["synchronizedFlickingOptions"]) {
41
- this._preventEvent(() => {
42
- this._synchronizedFlickingOptions = val;
43
- });
50
+ this._synchronizedFlickingOptions = val;
44
51
  }
45
52
 
46
53
  /** */
@@ -53,16 +60,20 @@ class Sync implements Plugin {
53
60
  }
54
61
 
55
62
  public init(flicking: Flicking): void {
63
+ const synced = this._synchronizedFlickingOptions;
64
+
56
65
  if (this._flicking) {
57
66
  this.destroy();
58
67
  }
59
68
 
60
69
  this._flicking = flicking;
61
70
 
62
- this._addEvents(this._synchronizedFlickingOptions);
71
+ this._addEvents();
72
+
73
+ synced.forEach(options => {
74
+ const { flicking: syncedFlicking } = options;
63
75
 
64
- this._synchronizedFlickingOptions.forEach(synchronizedFlickingOption => {
65
- this._updateClass(synchronizedFlickingOption, 0);
76
+ this._updateClass(options, syncedFlicking.defaultIndex);
66
77
  });
67
78
  }
68
79
 
@@ -73,57 +84,66 @@ class Sync implements Plugin {
73
84
  return;
74
85
  }
75
86
 
76
- this._removeEvents(this._synchronizedFlickingOptions);
87
+ this._removeEvents();
77
88
 
78
89
  this._flicking = null;
79
90
  }
80
91
 
81
92
  public update(): void {
82
- this._synchronizedFlickingOptions.forEach(({ flicking, activeClass }) => {
83
- this._updateClass(({ flicking, activeClass }), flicking.camera.position);
93
+ this._synchronizedFlickingOptions.forEach(options => {
94
+ this._updateClass(options, options.flicking.index);
84
95
  });
85
96
  }
86
97
 
87
98
  private _preventEvent(fn: () => void) {
88
- this._removeEvents(this._synchronizedFlickingOptions);
99
+ this._removeEvents();
89
100
  fn();
90
- this._addEvents(this._synchronizedFlickingOptions);
101
+ this._addEvents();
91
102
  }
92
103
 
93
- private _addEvents = (synchronizedFlickingOptions: SychronizableFlickingOptions[]): void => {
94
- synchronizedFlickingOptions.forEach(({ flicking, isSlidable, isClickable }) => {
95
- if (this._type === "camera") {
104
+ private _addEvents = (): void => {
105
+ const type = this._type;
106
+ const synced = this._synchronizedFlickingOptions;
107
+
108
+ synced.forEach(({ flicking, isSlidable, isClickable }) => {
109
+ if (type === SYNC.TYPE.CAMERA) {
96
110
  flicking.on(EVENTS.MOVE, this._onMove);
97
111
  flicking.on(EVENTS.MOVE_START, this._onMoveStart);
98
112
  flicking.on(EVENTS.MOVE_END, this._onMoveEnd);
99
113
  }
100
- if (this._type === "index" && isSlidable) {
114
+ if (type === SYNC.TYPE.INDEX && isSlidable) {
101
115
  flicking.on(EVENTS.WILL_CHANGE, this._onIndexChange);
116
+ flicking.on(EVENTS.WILL_RESTORE, this._onIndexChange);
102
117
  }
103
118
  if (isClickable) {
104
- flicking.on(EVENTS.SELECT, this._onIndexChange);
119
+ flicking.on(EVENTS.SELECT, this._onSelect);
105
120
  }
106
121
  });
107
122
  };
108
123
 
109
- private _removeEvents = (synchronizedFlickingOptions: SychronizableFlickingOptions[]): void => {
110
- synchronizedFlickingOptions.forEach(({ flicking, isSlidable, isClickable }) => {
111
- if (this._type === "camera") {
124
+ private _removeEvents = (): void => {
125
+ const type = this._type;
126
+ const synced = this._synchronizedFlickingOptions;
127
+
128
+ synced.forEach(({ flicking, isSlidable, isClickable }) => {
129
+ if (type === SYNC.TYPE.CAMERA) {
112
130
  flicking.off(EVENTS.MOVE, this._onMove);
113
131
  flicking.off(EVENTS.MOVE_START, this._onMoveStart);
114
132
  flicking.off(EVENTS.MOVE_END, this._onMoveEnd);
115
133
  }
116
- if (this._type === "index" && isSlidable) {
134
+ if (type === SYNC.TYPE.INDEX && isSlidable) {
117
135
  flicking.off(EVENTS.WILL_CHANGE, this._onIndexChange);
136
+ flicking.off(EVENTS.WILL_RESTORE, this._onIndexChange);
118
137
  }
119
138
  if (isClickable) {
120
- flicking.off(EVENTS.SELECT, this._onIndexChange);
139
+ flicking.off(EVENTS.SELECT, this._onSelect);
121
140
  }
122
141
  });
123
142
  };
124
143
 
125
- private _onIndexChange = (e: { index: number; currentTarget: Flicking }): void => {
144
+ private _onIndexChange = (e: WillChangeEvent): void => {
126
145
  const flicking = e.currentTarget;
146
+
127
147
  if (!flicking.initialized) {
128
148
  return;
129
149
  }
@@ -131,24 +151,28 @@ class Sync implements Plugin {
131
151
  this._synchronizeByIndex(flicking, e.index);
132
152
  };
133
153
 
134
- private _onMove = (e: { currentTarget: Flicking }): void => {
154
+ private _onMove = (e: MoveEvent): void => {
135
155
  const camera = e.currentTarget.camera;
136
156
  const progress = (camera.position - camera.range.min) / camera.rangeDiff;
137
157
 
138
158
  this._synchronizedFlickingOptions.forEach(({ flicking }) => {
139
- if (flicking !== e.currentTarget) {
140
- if (camera.position < camera.range.min) {
141
- void flicking.camera.lookAt(camera.position);
142
- } else if (camera.position > camera.range.max) {
143
- void flicking.camera.lookAt(flicking.camera.range.max + camera.position - camera.range.max);
144
- } else {
145
- void flicking.camera.lookAt(flicking.camera.range.min + flicking.camera.rangeDiff * progress);
146
- }
159
+ if (flicking === e.currentTarget) return;
160
+
161
+ let targetPosition = 0;
162
+
163
+ if (camera.position < camera.range.min) {
164
+ targetPosition = camera.position;
165
+ } else if (camera.position > camera.range.max) {
166
+ targetPosition = flicking.camera.range.max + camera.position - camera.range.max;
167
+ } else {
168
+ targetPosition = flicking.camera.range.min + flicking.camera.rangeDiff * progress;
147
169
  }
170
+
171
+ void flicking.camera.lookAt(targetPosition);
148
172
  });
149
173
  };
150
174
 
151
- private _onMoveStart = (e: { currentTarget: Flicking }): void => {
175
+ private _onMoveStart = (e: MoveStartEvent): void => {
152
176
  this._synchronizedFlickingOptions.forEach(({ flicking }) => {
153
177
  if (flicking !== e.currentTarget) {
154
178
  flicking.disableInput();
@@ -156,7 +180,7 @@ class Sync implements Plugin {
156
180
  });
157
181
  };
158
182
 
159
- private _onMoveEnd = (e: { currentTarget: Flicking }): void => {
183
+ private _onMoveEnd = (e: MoveEndEvent): void => {
160
184
  this._synchronizedFlickingOptions.forEach(({ flicking }) => {
161
185
  if (flicking !== e.currentTarget) {
162
186
  flicking.enableInput();
@@ -165,43 +189,47 @@ class Sync implements Plugin {
165
189
  });
166
190
  };
167
191
 
192
+ private _onSelect = (e: SelectEvent): void => {
193
+ void e.currentTarget.moveTo(e.index).catch(() => void 0);
194
+
195
+ this._synchronizeByIndex(e.currentTarget, e.index);
196
+ };
197
+
168
198
  private _synchronizeByIndex = (activeFlicking: Flicking, index: number): void => {
169
199
  const synchronizedFlickingOptions = this._synchronizedFlickingOptions;
170
- const activePanel = activeFlicking.panels.find(panel => panel.index === index);
171
- const lastPanel = activeFlicking.panels[activeFlicking.panels.length - 1];
172
-
173
- if (!activePanel) {
174
- return;
175
- }
176
200
 
177
201
  this._preventEvent(() => {
178
- synchronizedFlickingOptions.forEach(({ flicking, activeClass }) => {
179
- // calculate new target flicking position with active flicking size and target flicking size
180
- const targetLastPanel = flicking.panels[flicking.panels.length - 1];
181
- const targetPos = activePanel.position / (lastPanel.position + (lastPanel.size / 2)) * (targetLastPanel.position + (targetLastPanel.size / 2));
182
-
183
- flicking.control.moveToPosition(targetPos, 500).catch(() => void 0);
184
- if (activeClass) {
185
- this._updateClass(({ flicking, activeClass }), targetPos);
202
+ synchronizedFlickingOptions.forEach(options => {
203
+ // Active class should be applied same to the Flicking which triggered event
204
+ this._updateClass(options, index);
205
+
206
+ const { flicking } = options;
207
+ if (flicking === activeFlicking) return;
208
+
209
+ const targetIndex = clamp(index, 0, flicking.panels.length);
210
+
211
+ if (flicking.animating) {
212
+ // Reserve moveTo once previous animation is finished
213
+ flicking.once(EVENTS.MOVE_END, () => {
214
+ void flicking.moveTo(targetIndex).catch(() => void 0);
215
+ });
216
+ } else {
217
+ void flicking.moveTo(targetIndex);
186
218
  }
187
219
  });
188
220
  });
189
221
  };
190
222
 
191
- private _updateClass = (synchronizedFlickingOption: SychronizableFlickingOptions, pos: number): void => {
192
- const target = this._findNearsetPanel(synchronizedFlickingOption.flicking, pos);
193
- synchronizedFlickingOption.flicking.panels.forEach((panel) => panel.index === target.index ? addClass(panel.element, synchronizedFlickingOption.activeClass as string) : removeClass(panel.element, synchronizedFlickingOption.activeClass as string));
194
- };
223
+ private _updateClass = ({ flicking, activeClass }: SychronizableFlickingOptions, index: number): void => {
224
+ if (!activeClass) return;
195
225
 
196
- private _findNearsetPanel = (flicking: Flicking, pos: number): Panel => {
197
- const nearsetIndex = flicking.panels.reduce((nearest, panel, index) => Math.abs(panel.position - pos) <= nearest.range ? {
198
- index,
199
- range: Math.abs(panel.position - pos)
200
- } : nearest, {
201
- index: 0,
202
- range: Infinity
203
- }).index;
204
- return flicking.panels[nearsetIndex];
226
+ flicking.panels.forEach(panel => {
227
+ if (panel.index === index) {
228
+ addClass(panel.element, activeClass);
229
+ } else {
230
+ removeClass(panel.element, activeClass);
231
+ }
232
+ });
205
233
  };
206
234
  }
207
235
 
package/src/index.ts CHANGED
@@ -8,7 +8,8 @@ import Parallax from "./Parallax";
8
8
  import Fade from "./Fade";
9
9
  import AutoPlay from "./AutoPlay";
10
10
  import Arrow from "./Arrow";
11
- import Sync from "./Sync";
11
+ import Sync, { SyncOptions, SychronizableFlickingOptions } from "./Sync";
12
+ import Perspective from "./Perspective";
12
13
 
13
14
  export * from "./pagination";
14
15
 
@@ -17,7 +18,13 @@ export {
17
18
  Fade,
18
19
  AutoPlay,
19
20
  Arrow,
20
- Sync
21
+ Sync,
22
+ Perspective
23
+ };
24
+
25
+ export type {
26
+ SyncOptions,
27
+ SychronizableFlickingOptions
21
28
  };
22
29
 
23
30
  export * from "./const";
@@ -40,7 +40,7 @@ class BulletRenderer extends Renderer {
40
40
 
41
41
  bullet.addEventListener(BROWSER.TOUCH_START, e => {
42
42
  e.stopPropagation();
43
- });
43
+ }, { passive: true });
44
44
 
45
45
  bullet.addEventListener(BROWSER.CLICK, () => {
46
46
  flicking.moveTo(anchorPoint.panel.index)
@@ -46,7 +46,7 @@ class ScrollBulletRenderer extends Renderer {
46
46
 
47
47
  bullet.addEventListener(BROWSER.TOUCH_START, e => {
48
48
  e.stopPropagation();
49
- });
49
+ }, { passive: true });
50
50
 
51
51
  bullet.addEventListener(BROWSER.CLICK, () => {
52
52
  flicking.moveTo(anchorPoint.panel.index)
package/src/utils.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export const addClass = (el: HTMLElement, className: string) => {
2
+ if (!el) return;
3
+
2
4
  if (el.classList) {
3
5
  el.classList.add(className);
4
6
  } else {
@@ -11,6 +13,8 @@ export const addClass = (el: HTMLElement, className: string) => {
11
13
  };
12
14
 
13
15
  export const removeClass = (el: HTMLElement, className: string) => {
16
+ if (!el) return;
17
+
14
18
  if (el.classList) {
15
19
  el.classList.remove(className);
16
20
  } else {