@fastkit/scroller 0.16.0 → 0.17.0-next.1

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/scroller.mjs CHANGED
@@ -1,1416 +1,1387 @@
1
- import { EV } from '@fastkit/ev';
2
- import { visibilityManager } from '@fastkit/visibility';
3
- import { IN_WINDOW, removeUndef } from '@fastkit/helpers';
4
- import { TinyLogger } from '@fastkit/tiny-logger';
5
-
6
- // src/util.ts
1
+ import { EV } from "@fastkit/ev";
2
+ import { visibilityManager } from "@fastkit/visibility";
3
+ import { IN_WINDOW, removeUndef } from "@fastkit/helpers";
4
+ import { TinyLogger } from "@fastkit/tiny-logger";
5
+ //#region src/util.ts
7
6
  function isDocumentElement(el) {
8
- return el.constructor === HTMLHtmlElement;
7
+ return el.constructor === HTMLHtmlElement;
9
8
  }
10
- function isBodyElement(el) {
11
- return el.constructor === HTMLBodyElement;
9
+ function isBodyElement$1(el) {
10
+ return el.constructor === HTMLBodyElement;
12
11
  }
13
- var logger = new TinyLogger("scroller");
14
-
15
- // src/prevent-scroll.ts
16
- var SCROLLABLE_KEY_CODES = [32, 33, 34, 35, 36, 37, 38, 39, 40];
17
- var eventListenerOptions = {
18
- passive: false
19
- };
20
- var handleWheel = (e) => {
21
- e.preventDefault();
12
+ //#endregion
13
+ //#region src/logger.ts
14
+ const logger = new TinyLogger("scroller");
15
+ //#endregion
16
+ //#region src/prevent-scroll.ts
17
+ const SCROLLABLE_KEY_CODES = [
18
+ 32,
19
+ 33,
20
+ 34,
21
+ 35,
22
+ 36,
23
+ 37,
24
+ 38,
25
+ 39,
26
+ 40
27
+ ];
28
+ const eventListenerOptions = { passive: false };
29
+ const handleWheel = (e) => {
30
+ e.preventDefault();
22
31
  };
23
- var handleScroll = (e) => {
24
- const el = e.target;
25
- if (el && el.__ps_ctx__) {
26
- el.scrollTo(el.__ps_ctx__.lockPosition.x, el.__ps_ctx__.lockPosition.y);
27
- }
32
+ const handleScroll = (e) => {
33
+ const el = e.target;
34
+ if (el && el.__ps_ctx__) el.scrollTo(el.__ps_ctx__.lockPosition.x, el.__ps_ctx__.lockPosition.y);
28
35
  };
29
- var handleKeydown = (e) => {
30
- if (e.target && ["INPUT", "TEXTAREA"].includes(e.target.tagName)) {
31
- return;
32
- }
33
- if (SCROLLABLE_KEY_CODES.includes(e.which)) {
34
- e.preventDefault();
35
- }
36
+ const handleKeydown = (e) => {
37
+ if (e.target && ["INPUT", "TEXTAREA"].includes(e.target.tagName)) return;
38
+ if (SCROLLABLE_KEY_CODES.includes(e.which)) e.preventDefault();
36
39
  };
37
40
  function enableScroll(el) {
38
- const _el = el;
39
- if (!_el.__ps_ctx__) return;
40
- const { options } = _el.__ps_ctx__;
41
- _el.removeEventListener("wheel", handleWheel, eventListenerOptions);
42
- _el.removeEventListener("scroll", handleScroll, eventListenerOptions);
43
- _el.removeEventListener("keydown", handleKeydown);
44
- if (options.hideScrollbar) {
45
- _el.style.overflow = _el.__ps_ctx__.overflowOrigin;
46
- }
47
- delete _el.__ps_ctx__;
41
+ const _el = el;
42
+ if (!_el.__ps_ctx__) return;
43
+ const { options } = _el.__ps_ctx__;
44
+ _el.removeEventListener("wheel", handleWheel, eventListenerOptions);
45
+ _el.removeEventListener("scroll", handleScroll, eventListenerOptions);
46
+ _el.removeEventListener("keydown", handleKeydown);
47
+ if (options.hideScrollbar) _el.style.overflow = _el.__ps_ctx__.overflowOrigin;
48
+ delete _el.__ps_ctx__;
48
49
  }
49
50
  function disableScroll(el, opts = {}) {
50
- const { hideScrollbar = false } = opts;
51
- const _el = el;
52
- if (_el.__ps_ctx__) return;
53
- const options = {
54
- hideScrollbar
55
- };
56
- _el.__ps_ctx__ = {
57
- options,
58
- el: _el,
59
- overflowOrigin: _el.style.overflow,
60
- lockPosition: {
61
- x: _el.scrollLeft || _el.scrollX,
62
- y: _el.scrollTop || _el.scrollY
63
- }
64
- };
65
- if (options.hideScrollbar) {
66
- _el.style.overflow = "hidden";
67
- }
68
- _el.addEventListener("wheel", handleWheel, eventListenerOptions);
69
- _el.addEventListener("scroll", handleScroll, eventListenerOptions);
70
- _el.addEventListener("keydown", handleKeydown);
51
+ const { hideScrollbar = false } = opts;
52
+ const _el = el;
53
+ if (_el.__ps_ctx__) return;
54
+ const options = { hideScrollbar };
55
+ _el.__ps_ctx__ = {
56
+ options,
57
+ el: _el,
58
+ overflowOrigin: _el.style.overflow,
59
+ lockPosition: {
60
+ x: _el.scrollLeft || _el.scrollX,
61
+ y: _el.scrollTop || _el.scrollY
62
+ }
63
+ };
64
+ if (options.hideScrollbar) _el.style.overflow = "hidden";
65
+ _el.addEventListener("wheel", handleWheel, eventListenerOptions);
66
+ _el.addEventListener("scroll", handleScroll, eventListenerOptions);
67
+ _el.addEventListener("keydown", handleKeydown);
71
68
  }
72
-
73
- // src/scroll/schemes.ts
74
- var defaultBaseSettings = {
75
- duration: 500,
76
- easing: "ease",
77
- cancelable: true
69
+ //#endregion
70
+ //#region src/scroll/schemes.ts
71
+ const defaultBaseSettings = {
72
+ duration: 500,
73
+ easing: "ease",
74
+ cancelable: true
78
75
  };
79
- var defaultSettings = {
80
- get container() {
81
- return document.scrollingElement;
82
- },
83
- ...defaultBaseSettings
76
+ const defaultSettings = {
77
+ get container() {
78
+ return document.scrollingElement;
79
+ },
80
+ ...defaultBaseSettings
84
81
  };
85
-
86
- // src/bezier-easing.ts
82
+ //#endregion
83
+ //#region src/bezier-easing.ts
87
84
  function LinearEasing(x) {
88
- return x;
85
+ return x;
89
86
  }
90
- var { cbrt, sqrt, PI: \u03C0 } = Math;
91
- var x2t = (x, a, b, c, d) => {
92
- const q = a + b * x;
93
- const s = q ** 2 + c;
94
- if (s > 0) {
95
- const root = sqrt(s);
96
- return cbrt(q + root) + cbrt(q - root) - d;
97
- }
98
- const l = cbrt(sqrt(q * q - s));
99
- const angle = q ? Math.atan(sqrt(-s) / q) : -\u03C0 / 2;
100
- let \u03C6;
101
- if (b < 0) {
102
- \u03C6 = (q > 0 ? 2 * \u03C0 : \u03C0) - angle;
103
- } else if (d < 0) {
104
- \u03C6 = (q > 0 ? 2 * \u03C0 : -3 * \u03C0) + angle;
105
- } else {
106
- \u03C6 = (q > 0 ? 0 : \u03C0) + angle;
107
- }
108
- return 2 * l * Math.cos(\u03C6 / 3) - d;
87
+ const { cbrt, sqrt, PI: π } = Math;
88
+ const x2t = (x, a, b, c, d) => {
89
+ const q = a + b * x;
90
+ const s = q ** 2 + c;
91
+ if (s > 0) {
92
+ const root = sqrt(s);
93
+ return cbrt(q + root) + cbrt(q - root) - d;
94
+ }
95
+ const l = cbrt(sqrt(q * q - s));
96
+ const angle = q ? Math.atan(sqrt(-s) / q) : -π / 2;
97
+ let φ;
98
+ if (b < 0) φ = (q > 0 ? 2 * π : π) - angle;
99
+ else if (d < 0) φ = (q > 0 ? 2 * π : -3 * π) + angle;
100
+ else φ = (q > 0 ? 0 : π) + angle;
101
+ return 2 * l * Math.cos(φ / 3) - d;
109
102
  };
110
- var Y = (t, ay, by, cy) => ((ay * t + 3 * by) * t + cy) * t;
103
+ const Y = (t, ay, by, cy) => ((ay * t + 3 * by) * t + cy) * t;
111
104
  function bezier(mX1, mY1, mX2, mY2) {
112
- if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) {
113
- throw new Error("bezier x values must be in [0, 1] range");
114
- }
115
- if (mX1 === mY1 && mX2 === mY2) {
116
- return LinearEasing;
117
- }
118
- const a = 6 * (3 * mX1 - 3 * mX2 + 1);
119
- const b = 6 * (mX2 - 2 * mX1);
120
- const c = 3 * mX1;
121
- const a2 = a * a;
122
- const b2 = b * b;
123
- const d = b / a;
124
- const e = 3 * b * c / a2 - b2 * b / (a2 * a);
125
- const w1 = 2 * c / a - b2 / a2;
126
- const w = w1 * w1 * w1;
127
- const o = 3 / a;
128
- const ay = 3 * mY1 - 3 * mY2 + 1;
129
- const by = mY2 - 2 * mY1;
130
- const cy = 3 * mY1;
131
- const X2T = a ? x2t : LinearEasing;
132
- return function BezierEasing(x) {
133
- if (x === 0 || x === 1) {
134
- return x;
135
- }
136
- return Y(X2T(x, e, o, w, d), ay, by, cy);
137
- };
105
+ if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) throw new Error("bezier x values must be in [0, 1] range");
106
+ if (mX1 === mY1 && mX2 === mY2) return LinearEasing;
107
+ const a = 6 * (3 * mX1 - 3 * mX2 + 1);
108
+ const b = 6 * (mX2 - 2 * mX1);
109
+ const c = 3 * mX1;
110
+ const a2 = a * a;
111
+ const b2 = b * b;
112
+ const d = b / a;
113
+ const e = 3 * b * c / a2 - b2 * b / (a2 * a);
114
+ const w1 = 2 * c / a - b2 / a2;
115
+ const w = w1 * w1 * w1;
116
+ const o = 3 / a;
117
+ const ay = 3 * mY1 - 3 * mY2 + 1;
118
+ const by = mY2 - 2 * mY1;
119
+ const cy = 3 * mY1;
120
+ const X2T = a ? x2t : LinearEasing;
121
+ return function BezierEasing(x) {
122
+ if (x === 0 || x === 1) return x;
123
+ return Y(X2T(x, e, o, w, d), ay, by, cy);
124
+ };
138
125
  }
139
-
140
- // src/scroll/easings.ts
141
- var easings = {
142
- ease: [0.25, 0.1, 0.25, 1],
143
- linear: [0, 0, 1, 1],
144
- "ease-in": [0.42, 0, 1, 1],
145
- "ease-out": [0, 0, 0.58, 1],
146
- "ease-in-out": [0.42, 0, 0.58, 1]
126
+ //#endregion
127
+ //#region src/scroll/easings.ts
128
+ const easings = {
129
+ ease: [
130
+ .25,
131
+ .1,
132
+ .25,
133
+ 1
134
+ ],
135
+ linear: [
136
+ 0,
137
+ 0,
138
+ 1,
139
+ 1
140
+ ],
141
+ "ease-in": [
142
+ .42,
143
+ 0,
144
+ 1,
145
+ 1
146
+ ],
147
+ "ease-out": [
148
+ 0,
149
+ 0,
150
+ .58,
151
+ 1
152
+ ],
153
+ "ease-in-out": [
154
+ .42,
155
+ 0,
156
+ .58,
157
+ 1
158
+ ]
147
159
  };
148
- var easings_default = easings;
149
-
150
- // src/scroll/util.ts
151
- function isBodyElement2(el) {
152
- return el.tagName.toLowerCase() === "body";
160
+ //#endregion
161
+ //#region src/scroll/util.ts
162
+ function isBodyElement(el) {
163
+ return el.tagName.toLowerCase() === "body";
153
164
  }
154
165
  function getContainerDimension(el) {
155
- if (isBodyElement2(el)) {
156
- const documentElement = document.documentElement;
157
- return {
158
- // width: window.innerWidth,
159
- // height: window.innerHeight,
160
- width: documentElement.clientWidth,
161
- height: documentElement.clientWidth
162
- };
163
- }
164
- return {
165
- width: el.clientWidth,
166
- height: el.clientHeight
167
- };
166
+ if (isBodyElement(el)) {
167
+ const documentElement = document.documentElement;
168
+ return {
169
+ width: documentElement.clientWidth,
170
+ height: documentElement.clientWidth
171
+ };
172
+ }
173
+ return {
174
+ width: el.clientWidth,
175
+ height: el.clientHeight
176
+ };
168
177
  }
169
178
  function $(selectorOrElement) {
170
- if (typeof selectorOrElement !== "string")
171
- return selectorOrElement;
172
- return document.querySelector(selectorOrElement);
179
+ if (typeof selectorOrElement !== "string") return selectorOrElement;
180
+ return document.querySelector(selectorOrElement);
173
181
  }
174
182
  function cumulativeOffset(element) {
175
- let top = 0;
176
- let left = 0;
177
- let el = element;
178
- while (el) {
179
- top += el.offsetTop || 0;
180
- left += el.offsetLeft || 0;
181
- el = el.offsetParent;
182
- }
183
- return {
184
- top,
185
- left
186
- };
183
+ let top = 0;
184
+ let left = 0;
185
+ let el = element;
186
+ while (el) {
187
+ top += el.offsetTop || 0;
188
+ left += el.offsetLeft || 0;
189
+ el = el.offsetParent;
190
+ }
191
+ return {
192
+ top,
193
+ left
194
+ };
187
195
  }
188
196
  function on(element, events, handler, opts = { passive: false }) {
189
- if (!Array.isArray(events)) events = [events];
190
- for (let i = 0; i < events.length; i++) {
191
- element.addEventListener(events[i], handler, opts);
192
- }
197
+ if (!Array.isArray(events)) events = [events];
198
+ for (let i = 0; i < events.length; i++) element.addEventListener(events[i], handler, opts);
193
199
  }
194
200
  function off(element, events, handler) {
195
- if (!Array.isArray(events)) events = [events];
196
- for (let i = 0; i < events.length; i++) {
197
- element.removeEventListener(events[i], handler);
198
- }
201
+ if (!Array.isArray(events)) events = [events];
202
+ for (let i = 0; i < events.length; i++) element.removeEventListener(events[i], handler);
199
203
  }
200
204
  function error(message) {
201
- return new Error(`[scroll] ${message}`);
205
+ return /* @__PURE__ */ new Error(`[scroll] ${message}`);
202
206
  }
203
-
204
- // src/scroll/scroll-by-internal.ts
205
- var abortEvents = [
206
- "mousedown",
207
- "wheel",
208
- "DOMMouseScroll",
209
- "mousewheel",
210
- "keyup",
211
- "touchmove"
207
+ //#endregion
208
+ //#region src/scroll/scroll-by-internal.ts
209
+ const abortEvents = [
210
+ "mousedown",
211
+ "wheel",
212
+ "DOMMouseScroll",
213
+ "mousewheel",
214
+ "keyup",
215
+ "touchmove"
212
216
  ];
213
217
  function scroll(diffX, diffY, options = {}, _computedValues) {
214
- let $container;
215
- let initialX;
216
- let initialY;
217
- let targetX;
218
- let targetY;
219
- const _options = { ...defaultSettings, ...removeUndef(options) };
220
- const {
221
- container,
222
- duration,
223
- easing,
224
- cancelable,
225
- onProgress,
226
- onCancel,
227
- onDone
228
- } = _options;
229
- const x = diffX !== 0;
230
- const y = diffY !== 0;
231
- if (_computedValues) {
232
- $container = _computedValues.$container;
233
- initialX = _computedValues.initialX;
234
- initialY = _computedValues.initialY;
235
- targetX = _computedValues.targetX;
236
- targetY = _computedValues.targetY;
237
- } else {
238
- $container = $(container);
239
- if (!$container) throw error(`missing container ${container}`);
240
- initialX = $container.scrollLeft;
241
- initialY = $container.scrollTop;
242
- targetX = initialX + diffX;
243
- targetY = initialY + diffY;
244
- }
245
- const { scrollWidth, scrollHeight } = $container;
246
- const { width, height } = getContainerDimension($container);
247
- const overflowX = targetX + width - scrollWidth;
248
- const overflowY = targetY + height - scrollHeight;
249
- if (overflowX > 0) {
250
- diffX -= overflowX;
251
- targetX -= overflowX;
252
- }
253
- if (overflowY > 0) {
254
- diffY -= overflowY;
255
- targetY -= overflowY;
256
- }
257
- let doneResolver;
258
- let timeStart = 0;
259
- let timeElapsed;
260
- const callbackValues = {
261
- container: $container,
262
- progress: 0,
263
- aborted: false,
264
- abortEventSource: null
265
- };
266
- const result = {
267
- cancel: canceller,
268
- promise: new Promise((resolve) => {
269
- doneResolver = resolve;
270
- }),
271
- plans: {
272
- x: diffX,
273
- y: diffY
274
- }
275
- };
276
- if (diffY === 0 && diffX === 0 || !!$container.__ps_ctx__)
277
- return initialAbort();
278
- let easingValues;
279
- if (!easing) {
280
- easingValues = easings_default.ease;
281
- } else if (typeof easing === "string") {
282
- easingValues = easings_default[_options.easing];
283
- } else {
284
- easingValues = easing;
285
- }
286
- const easingFn = bezier.apply(
287
- bezier,
288
- easingValues
289
- );
290
- on($container, abortEvents, abortFn, { passive: true });
291
- window.requestAnimationFrame(step);
292
- return result;
293
- function doneResolve() {
294
- doneResolver();
295
- }
296
- function canceller(e = null, checkCancelable = false) {
297
- if (checkCancelable && !cancelable) return;
298
- off($container, abortEvents, abortFn);
299
- callbackValues.abortEventSource = e;
300
- callbackValues.aborted = true;
301
- onCancel && onCancel(callbackValues);
302
- }
303
- function abortFn(e) {
304
- canceller(e, true);
305
- }
306
- function initialAbort(e = null) {
307
- canceller(e);
308
- doneResolve();
309
- return result;
310
- }
311
- function step(timestamp) {
312
- if (callbackValues.aborted) return done();
313
- if (!timeStart) timeStart = timestamp;
314
- timeElapsed = timestamp - timeStart;
315
- let progress = Math.min(timeElapsed / duration, 1);
316
- progress = easingFn(progress);
317
- callbackValues.progress = progress;
318
- topLeft(initialY + diffY * progress, initialX + diffX * progress);
319
- onProgress && onProgress(callbackValues);
320
- timeElapsed < duration ? window.requestAnimationFrame(step) : done();
321
- }
322
- function topLeft(top, left) {
323
- if (y) $container.scrollTop = top;
324
- if (x) $container.scrollLeft = left;
325
- }
326
- function done() {
327
- if (!callbackValues.aborted) topLeft(targetY, targetX);
328
- timeStart = 0;
329
- off($container, abortEvents, abortFn);
330
- callbackValues.progress = 1;
331
- doneResolve();
332
- if (!callbackValues.aborted && onDone) onDone(callbackValues);
333
- }
218
+ let $container;
219
+ let initialX;
220
+ let initialY;
221
+ let targetX;
222
+ let targetY;
223
+ const _options = {
224
+ ...defaultSettings,
225
+ ...removeUndef(options)
226
+ };
227
+ const { container, duration, easing, cancelable, onProgress, onCancel, onDone } = _options;
228
+ const x = diffX !== 0;
229
+ const y = diffY !== 0;
230
+ if (_computedValues) {
231
+ $container = _computedValues.$container;
232
+ initialX = _computedValues.initialX;
233
+ initialY = _computedValues.initialY;
234
+ targetX = _computedValues.targetX;
235
+ targetY = _computedValues.targetY;
236
+ } else {
237
+ $container = $(container);
238
+ if (!$container) throw error(`missing container ${container}`);
239
+ initialX = $container.scrollLeft;
240
+ initialY = $container.scrollTop;
241
+ targetX = initialX + diffX;
242
+ targetY = initialY + diffY;
243
+ }
244
+ const { scrollWidth, scrollHeight } = $container;
245
+ const { width, height } = getContainerDimension($container);
246
+ const overflowX = targetX + width - scrollWidth;
247
+ const overflowY = targetY + height - scrollHeight;
248
+ if (overflowX > 0) {
249
+ diffX -= overflowX;
250
+ targetX -= overflowX;
251
+ }
252
+ if (overflowY > 0) {
253
+ diffY -= overflowY;
254
+ targetY -= overflowY;
255
+ }
256
+ let doneResolver;
257
+ let timeStart = 0;
258
+ let timeElapsed;
259
+ const callbackValues = {
260
+ container: $container,
261
+ progress: 0,
262
+ aborted: false,
263
+ abortEventSource: null
264
+ };
265
+ const result = {
266
+ cancel: canceller,
267
+ promise: new Promise((resolve) => {
268
+ doneResolver = resolve;
269
+ }),
270
+ plans: {
271
+ x: diffX,
272
+ y: diffY
273
+ }
274
+ };
275
+ if (diffY === 0 && diffX === 0 || !!$container.__ps_ctx__) return initialAbort();
276
+ let easingValues;
277
+ if (!easing) easingValues = easings.ease;
278
+ else if (typeof easing === "string") easingValues = easings[_options.easing];
279
+ else easingValues = easing;
280
+ const easingFn = bezier.apply(bezier, easingValues);
281
+ on($container, abortEvents, abortFn, { passive: true });
282
+ window.requestAnimationFrame(step);
283
+ return result;
284
+ function doneResolve() {
285
+ doneResolver();
286
+ }
287
+ function canceller(e = null, checkCancelable = false) {
288
+ if (checkCancelable && !cancelable) return;
289
+ off($container, abortEvents, abortFn);
290
+ callbackValues.abortEventSource = e;
291
+ callbackValues.aborted = true;
292
+ onCancel && onCancel(callbackValues);
293
+ }
294
+ function abortFn(e) {
295
+ canceller(e, true);
296
+ }
297
+ function initialAbort(e = null) {
298
+ canceller(e);
299
+ doneResolve();
300
+ return result;
301
+ }
302
+ function step(timestamp) {
303
+ if (callbackValues.aborted) return done();
304
+ if (!timeStart) timeStart = timestamp;
305
+ timeElapsed = timestamp - timeStart;
306
+ let progress = Math.min(timeElapsed / duration, 1);
307
+ progress = easingFn(progress);
308
+ callbackValues.progress = progress;
309
+ topLeft(initialY + diffY * progress, initialX + diffX * progress);
310
+ onProgress && onProgress(callbackValues);
311
+ timeElapsed < duration ? window.requestAnimationFrame(step) : done();
312
+ }
313
+ function topLeft(top, left) {
314
+ if (y) $container.scrollTop = top;
315
+ if (x) $container.scrollLeft = left;
316
+ }
317
+ function done() {
318
+ if (!callbackValues.aborted) topLeft(targetY, targetX);
319
+ timeStart = 0;
320
+ off($container, abortEvents, abortFn);
321
+ callbackValues.progress = 1;
322
+ doneResolve();
323
+ if (!callbackValues.aborted && onDone) onDone(callbackValues);
324
+ }
334
325
  }
335
-
336
- // src/scroll/scroll-by.ts
326
+ //#endregion
327
+ //#region src/scroll/scroll-by.ts
328
+ /**
329
+ * 指定の差分だけコンテナをスクロールします。
330
+ * @param diffX - 横軸の移動量(px)です。デフォルトは0です。
331
+ * @param diffY - 縦軸の移動量(px)です。デフォルトは0です。
332
+ * @param options - スクロールオプション
333
+ */
337
334
  function scrollBy(diffX, diffY, options) {
338
- return scroll(diffX, diffY, options);
335
+ return scroll(diffX, diffY, options);
339
336
  }
340
-
341
- // src/scroll/scroll-to.ts
337
+ //#endregion
338
+ //#region src/scroll/scroll-to.ts
339
+ /**
340
+ * 任意の位置(px)へコンテナをスクロールします。
341
+ * @param scrollPosition - スクロール先を指定します。x, y 共にオプショナルなるです。未指定の軸は現在のスクロール値のまま保持されます。
342
+ * @param options - スクロールオプション
343
+ */
342
344
  function scrollTo(scrollPosition, options = {}) {
343
- let { x, y } = scrollPosition;
344
- const container = options.container || defaultSettings.container;
345
- const $container = $(container);
346
- if (!$container) throw error(`missing container ${container}`);
347
- const initialY = $container.scrollTop;
348
- const initialX = $container.scrollLeft;
349
- if (x === void 0) x = initialX;
350
- if (y === void 0) y = initialY;
351
- const diffX = x - initialX;
352
- const diffY = y - initialY;
353
- return scroll(diffX, diffY, options, {
354
- $container,
355
- initialX,
356
- initialY,
357
- targetX: x,
358
- targetY: y
359
- });
345
+ let { x, y } = scrollPosition;
346
+ const container = options.container || defaultSettings.container;
347
+ const $container = $(container);
348
+ if (!$container) throw error(`missing container ${container}`);
349
+ const initialY = $container.scrollTop;
350
+ const initialX = $container.scrollLeft;
351
+ if (x === void 0) x = initialX;
352
+ if (y === void 0) y = initialY;
353
+ return scroll(x - initialX, y - initialY, options, {
354
+ $container,
355
+ initialX,
356
+ initialY,
357
+ targetX: x,
358
+ targetY: y
359
+ });
360
360
  }
361
-
362
- // src/scroll/scroll-to-element.ts
363
- var scrollToElementSettingsDefaults = {
364
- offset: 0,
365
- x: false,
366
- y: true
361
+ //#endregion
362
+ //#region src/scroll/scroll-to-element.ts
363
+ /**
364
+ * 要素スクロール利用事のデフォルト設定です。
365
+ * {@link ScrollToElementSettings}
366
+ */
367
+ const scrollToElementSettingsDefaults = {
368
+ offset: 0,
369
+ x: false,
370
+ y: true
367
371
  };
372
+ /**
373
+ * 任意の要素の位置へスクロールします。
374
+ * @param target - スクロール先の要素
375
+ * @param options - スクロールオプション
376
+ */
368
377
  function scrollToElement(target, options = {}) {
369
- const _options = { ...scrollToElementSettingsDefaults, ...options };
370
- const { x, y } = _options;
371
- const offsetSource = _options.offset;
372
- const offset = typeof offsetSource === "number" ? { x: offsetSource, y: offsetSource } : offsetSource;
373
- const $target = $(target);
374
- if (!$target) throw error(`missing element ${target}`);
375
- const container = _options.container || defaultSettings.container;
376
- const $container = $(container);
377
- if (!$container) throw error(`missing container ${container}`);
378
- const cumulativeOffsetContainer = cumulativeOffset($container);
379
- const cumulativeOffsetTarget = cumulativeOffset($target);
380
- const initialY = $container.scrollTop;
381
- const initialX = $container.scrollLeft;
382
- const targetY = cumulativeOffsetTarget.top - cumulativeOffsetContainer.top + (offset.y || 0);
383
- const targetX = cumulativeOffsetTarget.left - cumulativeOffsetContainer.left + (offset.x || 0);
384
- const diffX = x ? targetX - initialX : 0;
385
- const diffY = y ? targetY - initialY : 0;
386
- return scroll(diffX, diffY, _options, {
387
- $container,
388
- initialX,
389
- initialY,
390
- targetX,
391
- targetY
392
- });
378
+ const _options = {
379
+ ...scrollToElementSettingsDefaults,
380
+ ...options
381
+ };
382
+ const { x, y } = _options;
383
+ const offsetSource = _options.offset;
384
+ const offset = typeof offsetSource === "number" ? {
385
+ x: offsetSource,
386
+ y: offsetSource
387
+ } : offsetSource;
388
+ const $target = $(target);
389
+ if (!$target) throw error(`missing element ${target}`);
390
+ const container = _options.container || defaultSettings.container;
391
+ const $container = $(container);
392
+ if (!$container) throw error(`missing container ${container}`);
393
+ const cumulativeOffsetContainer = cumulativeOffset($container);
394
+ const cumulativeOffsetTarget = cumulativeOffset($target);
395
+ const initialY = $container.scrollTop;
396
+ const initialX = $container.scrollLeft;
397
+ const targetY = cumulativeOffsetTarget.top - cumulativeOffsetContainer.top + (offset.y || 0);
398
+ const targetX = cumulativeOffsetTarget.left - cumulativeOffsetContainer.left + (offset.x || 0);
399
+ return scroll(x ? targetX - initialX : 0, y ? targetY - initialY : 0, _options, {
400
+ $container,
401
+ initialX,
402
+ initialY,
403
+ targetX,
404
+ targetY
405
+ });
393
406
  }
394
-
395
- // src/scroll/scroll-to-side.ts
407
+ //#endregion
408
+ //#region src/scroll/scroll-to-side.ts
409
+ /**
410
+ * コンテナをいずれかの辺までスクロールします。
411
+ * @param targets - 辺を指定します。シングルの文字列、及び配列に対応しています。
412
+ * @param options - スクロールオプション
413
+ */
396
414
  function scrollToSide(targets, options) {
397
- const sides = typeof targets === "string" ? [targets] : targets;
398
- const position = {};
399
- const hasRight = sides.includes("right");
400
- const hasBottom = sides.includes("bottom");
401
- if (sides.includes("top")) {
402
- position.y = 0;
403
- }
404
- if (sides.includes("left")) {
405
- position.x = 0;
406
- }
407
- if (hasRight || hasBottom) {
408
- const container = options && options.container || defaultSettings.container;
409
- const $container = $(container);
410
- if (!$container) throw error(`missing container ${container}`);
411
- if (hasRight) position.x = $container.scrollWidth;
412
- if (hasBottom) position.y = $container.scrollHeight;
413
- }
414
- return scrollTo(position, options);
415
+ const sides = typeof targets === "string" ? [targets] : targets;
416
+ const position = {};
417
+ const hasRight = sides.includes("right");
418
+ const hasBottom = sides.includes("bottom");
419
+ if (sides.includes("top")) position.y = 0;
420
+ if (sides.includes("left")) position.x = 0;
421
+ if (hasRight || hasBottom) {
422
+ const container = options && options.container || defaultSettings.container;
423
+ const $container = $(container);
424
+ if (!$container) throw error(`missing container ${container}`);
425
+ if (hasRight) position.x = $container.scrollWidth;
426
+ if (hasBottom) position.y = $container.scrollHeight;
427
+ }
428
+ return scrollTo(position, options);
415
429
  }
430
+ /**
431
+ * コンテナを上辺までスクロールします。
432
+ * @param options - スクロールオプション
433
+ */
416
434
  function scrollToTop(options) {
417
- return scrollToSide("top", options);
435
+ return scrollToSide("top", options);
418
436
  }
437
+ /**
438
+ * コンテナを右辺までスクロールします。
439
+ * @param options - スクロールオプション
440
+ */
419
441
  function scrollToRight(options) {
420
- return scrollToSide("right", options);
442
+ return scrollToSide("right", options);
421
443
  }
444
+ /**
445
+ * コンテナを下辺までスクロールします。
446
+ * @param options - スクロールオプション
447
+ */
422
448
  function scrollToBottom(options) {
423
- return scrollToSide("bottom", options);
449
+ return scrollToSide("bottom", options);
424
450
  }
451
+ /**
452
+ * コンテナを左辺までスクロールします。
453
+ * @param options - スクロールオプション
454
+ */
425
455
  function scrollToLeft(options) {
426
- return scrollToSide("left", options);
456
+ return scrollToSide("left", options);
427
457
  }
458
+ /**
459
+ * コンテナを左上コーナーまでスクロールします。
460
+ * @param options - スクロールオプション
461
+ */
428
462
  function scrollToLeftTop(options) {
429
- return scrollToSide(["left", "top"], options);
463
+ return scrollToSide(["left", "top"], options);
430
464
  }
465
+ /**
466
+ * コンテナを左下コーナーまでスクロールします。
467
+ * @param options - スクロールオプション
468
+ */
431
469
  function scrollToLeftBottom(options) {
432
- return scrollToSide(["left", "bottom"], options);
470
+ return scrollToSide(["left", "bottom"], options);
433
471
  }
472
+ /**
473
+ * コンテナを右上コーナーまでスクロールします。
474
+ * @param options - スクロールオプション
475
+ */
434
476
  function scrollToRightTop(options) {
435
- return scrollToSide(["right", "top"], options);
477
+ return scrollToSide(["right", "top"], options);
436
478
  }
479
+ /**
480
+ * コンテナを右下コーナーまでスクロールします。
481
+ * @param options - スクロールオプション
482
+ */
437
483
  function scrollToRightBottom(options) {
438
- return scrollToSide(["right", "bottom"], options);
484
+ return scrollToSide(["right", "bottom"], options);
439
485
  }
440
-
441
- // src/scroller.ts
442
- var ScrollerState = /* @__PURE__ */ ((ScrollerState2) => {
443
- ScrollerState2["Pending"] = "pending";
444
- ScrollerState2["Ready"] = "ready";
445
- ScrollerState2["Running"] = "running";
446
- ScrollerState2["Destroyed"] = "destroyed";
447
- return ScrollerState2;
448
- })(ScrollerState || {});
449
- var scrollerObservableKeys = [
450
- "state",
451
- "isPending",
452
- "isReady",
453
- "isRunning",
454
- "isDestroyed",
455
- "scrollEnabled",
456
- "containerWidth",
457
- "containerHeight",
458
- "scrollWidth",
459
- "scrollHeight",
460
- "scrollableX",
461
- "scrollableY",
462
- "scrollTop",
463
- "scrollLeft",
464
- "scrollRight",
465
- "scrollBottom",
466
- "lastAxis",
467
- "lastDirection",
468
- "lastYDirection",
469
- "lastXDirection",
470
- "nowScrolling"
486
+ //#endregion
487
+ //#region src/scroller.ts
488
+ /**
489
+ * Scrollerの状態を示します。
490
+ */
491
+ let ScrollerState = /* @__PURE__ */ function(ScrollerState) {
492
+ /**
493
+ * Scrollerが初期化されていない(Elementが設定されていない)状態を示します。
494
+ */
495
+ ScrollerState["Pending"] = "pending";
496
+ /**
497
+ * Scrollerが初期化されているが、[[Scroller.el]]のリサイズやスクロールのイベント監視が動作していない状態を示します。
498
+ */
499
+ ScrollerState["Ready"] = "ready";
500
+ /**
501
+ * Scrollerが初期化されていて、[[Scroller.el]]のリサイズやスクロールのイベント監視が動作している状態を示します。
502
+ */
503
+ ScrollerState["Running"] = "running";
504
+ /**
505
+ * [[Scroller.destroy]]が実行され、Scrollerが利用不可である状態を示します。
506
+ */
507
+ ScrollerState["Destroyed"] = "destroyed";
508
+ return ScrollerState;
509
+ }({});
510
+ const scrollerObservableKeys = [
511
+ "state",
512
+ "isPending",
513
+ "isReady",
514
+ "isRunning",
515
+ "isDestroyed",
516
+ "scrollEnabled",
517
+ "containerWidth",
518
+ "containerHeight",
519
+ "scrollWidth",
520
+ "scrollHeight",
521
+ "scrollableX",
522
+ "scrollableY",
523
+ "scrollTop",
524
+ "scrollLeft",
525
+ "scrollRight",
526
+ "scrollBottom",
527
+ "lastAxis",
528
+ "lastDirection",
529
+ "lastYDirection",
530
+ "lastXDirection",
531
+ "nowScrolling"
471
532
  ];
533
+ /**
534
+ * 任意のElement(or HTML Document)のスクロールやサイズ変更を監視し、その情報を通知するクラスです。<br>
535
+ * <a href="https://dadajam4.github.io/dadajam4/ev/classes/_ev_.ev.html" target="_blank">EV</a>を継承しており、イベントの購読[[Scroller.on]]等のインターフェースを利用するか、
536
+ * [[Scroller.observe]]メソッドを利用します。<br>
537
+ * [[Scroller.on]]、[[Scroller.once]]で購読可能なイベントについては[[ScrollerEventMap]]を参照してください。
538
+ */
472
539
  var Scroller = class extends EV {
473
- /**
474
- * Scrollerクラスの状態を監視&同期するオブジェクトが
475
- * 保有すべきプロパティ一のキーの配列です。
476
- */
477
- static scrollerObservableKeys = scrollerObservableKeys;
478
- /**
479
- * Scrollerの状態を示すenum値です。
480
- * {@link ScrollerState}
481
- */
482
- static States = ScrollerState;
483
- /**
484
- * スクロールを検知してから、移動がなくなった際に、何ms後にスクロール終了と判定するかのインターバル値を示します。
485
- * デフォルトは500です。
486
- */
487
- scrollingJudgeInterval = 500;
488
- /**
489
- * 縦、横のどちらのスクロールを基準とするかを示します。
490
- * デフォルトはyです。<br>
491
- * この設定は[[Scroller.toElement]]のデフォルト値にも影響します。
492
- */
493
- baseAxis = "y";
494
- /**
495
- * スクロール系メソッド[[Scroller.to]]等を利用する際のデフォルトの設定を示します。
496
- */
497
- scrollSettingsDefaults = { ...defaultBaseSettings };
498
- /**
499
- * [[Scroller.toElement]]のデフォルトオプションの設定を示します。
500
- */
501
- scrollToElementSettingsDefaults = {
502
- ...scrollToElementSettingsDefaults
503
- };
504
- scrollSizeObserver;
505
- /**
506
- * 設定されたElement要素です。
507
- * 初期化が完了していない時には本getterはundefinedを返却する事に注意してください。
508
- */
509
- get el() {
510
- return this._el;
511
- }
512
- /**
513
- * 現在の状態です。<br>
514
- * {@link ScrollerState}
515
- */
516
- get state() {
517
- return this._state;
518
- }
519
- /**
520
- * 未初期化である場合trueを示します。
521
- */
522
- get isPending() {
523
- return this._state === "pending" /* Pending */;
524
- }
525
- /**
526
- * 初期化済み&停止状態である場合trueを示します。
527
- */
528
- get isReady() {
529
- return this._state === "ready" /* Ready */;
530
- }
531
- /**
532
- * 初期化済み&動作中である場合trueを示します。
533
- */
534
- get isRunning() {
535
- return this._state === "running" /* Running */;
536
- }
537
- /**
538
- * インスタンスが破棄済みである場合trueを示します。
539
- */
540
- get isDestroyed() {
541
- return this._state === "destroyed" /* Destroyed */;
542
- }
543
- /**
544
- * スクロールの有効状態を取得します
545
- */
546
- get scrollEnabled() {
547
- return this._scrollStoppers.length === 0;
548
- }
549
- /**
550
- * スクロール要素の幅を示します。
551
- */
552
- get containerWidth() {
553
- return this._containerWidth;
554
- }
555
- /**
556
- * スクロール要素の高さを示します。
557
- */
558
- get containerHeight() {
559
- return this._containerHeight;
560
- }
561
- /**
562
- * スクロール要素内のコンテンツの幅を示します。
563
- */
564
- get scrollWidth() {
565
- return this._scrollWidth;
566
- }
567
- /**
568
- * スクロール要素内のコンテンツの高さを示します。
569
- */
570
- get scrollHeight() {
571
- return this._scrollHeight;
572
- }
573
- /**
574
- * x軸にスクロール可能な場合trueを示します
575
- */
576
- get scrollableX() {
577
- return this._scrollWidth > this._containerWidth;
578
- }
579
- /**
580
- * y軸にスクロール可能な場合trueを示します
581
- */
582
- get scrollableY() {
583
- return this._scrollHeight > this._containerHeight;
584
- }
585
- /**
586
- * 現在の上辺からのスクロール量を示します。
587
- */
588
- get scrollTop() {
589
- return this._scrollTop;
590
- }
591
- set scrollTop(scrollTop) {
592
- if (!this.el) return;
593
- this.el.scrollTop = scrollTop;
594
- }
595
- /**
596
- * 現在の右辺からのスクロール量を示します。
597
- */
598
- get scrollRight() {
599
- return this._scrollRight;
600
- }
601
- set scrollRight(scrollRight) {
602
- if (!this.el) return;
603
- this.el.scrollLeft = this._scrollWidth - this._containerWidth - scrollRight;
604
- }
605
- /**
606
- * 現在の下辺からのスクロール量を示します。
607
- */
608
- get scrollBottom() {
609
- return this._scrollBottom;
610
- }
611
- set scrollBottom(scrollBottom) {
612
- if (!this.el) return;
613
- this.el.scrollTop = this._scrollHeight - this._containerHeight - scrollBottom;
614
- }
615
- /**
616
- * 現在の左辺からのスクロール量を示します。
617
- */
618
- get scrollLeft() {
619
- return this._scrollLeft;
620
- }
621
- set scrollLeft(scrollLeft) {
622
- if (!this.el) return;
623
- this.el.scrollLeft = scrollLeft;
624
- }
625
- /**
626
- * 現在スクロール中である場合trueを示します。
627
- */
628
- get nowScrolling() {
629
- return this._nowScrolling;
630
- }
631
- /**
632
- * 最後に検知したスクロールの軸を示します。
633
- */
634
- get lastAxis() {
635
- return this._lastAxis;
636
- }
637
- /**
638
- * 最後に検知したスクロールの方向を示します。
639
- */
640
- get lastDirection() {
641
- return this._lastDirection;
642
- }
643
- /**
644
- * 最後に検知したスクロールの垂直方向を示します。
645
- */
646
- get lastYDirection() {
647
- return this._lastYDirection;
648
- }
649
- /**
650
- * 最後に検知したスクロールの水平方向を示します。
651
- */
652
- get lastXDirection() {
653
- return this._lastXDirection;
654
- }
655
- /**
656
- * 最後に検知したスクロールにより通知した情報を示します。
657
- */
658
- get lastPayload() {
659
- return {
660
- top: this._scrollTop,
661
- left: this._scrollLeft,
662
- bottom: this._scrollBottom,
663
- right: this._scrollRight,
664
- axis: this._lastAxis,
665
- direction: this._lastDirection,
666
- directionX: this._lastXDirection,
667
- directionY: this._lastYDirection,
668
- tickedX: this._tickedX,
669
- tickedY: this._tickedY,
670
- totalX: this._lastTotalX,
671
- totalY: this._lastTotalY
672
- };
673
- }
674
- _el;
675
- _eventTarget;
676
- _isDocumentElement = false;
677
- _isBodyElement = false;
678
- _isRootElement = false;
679
- _state = "pending" /* Pending */;
680
- _containerWidth = 0;
681
- _containerHeight = 0;
682
- _scrollWidth = 0;
683
- _scrollHeight = 0;
684
- _scrollTop = 0;
685
- _scrollRight = 0;
686
- _scrollBottom = 0;
687
- _scrollLeft = 0;
688
- _lastAxis;
689
- _lastDirection;
690
- _lastYDirection = "top";
691
- _lastXDirection = "left";
692
- _nowScrolling = false;
693
- // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
694
- _readyResolvers = [];
695
- _scrollingJudgeTimerId = null;
696
- _startX = 0;
697
- _startY = 0;
698
- _tickedX = 0;
699
- _tickedY = 0;
700
- _lastTotalX = 0;
701
- _lastTotalY = 0;
702
- _scrollListener;
703
- _resizeListener;
704
- _resizeObserver;
705
- _scrollToResult = null;
706
- _observers = [];
707
- _scrollStoppers = [];
708
- _scrollSizeObserverPollingId = null;
709
- _scrollSizeObserverSuspended = false;
710
- _visibilityListener;
711
- /**
712
- * Scrollerインスタンスを作成します。
713
- * コンテキストとなるElementをこの時点で指定するか否かは任意です。
714
- *
715
- * @param settingOrElementOrQueryString - 任意です。{@link ScrollerSetting}か Element(or cssクエリセレクタ文字列)を直接指定します。この時点でElementを指定しない場合は、[[setElement]]を実行するまでインスタンスは動作しません。
716
- */
717
- constructor(settingOrElementOrQueryString = {}) {
718
- super();
719
- const convertedSetting = typeof settingOrElementOrQueryString === "string" || settingOrElementOrQueryString === null || IN_WINDOW && settingOrElementOrQueryString instanceof Element ? settingOrElementOrQueryString = {
720
- el: settingOrElementOrQueryString
721
- } : settingOrElementOrQueryString;
722
- if (convertedSetting.scrollingJudgeInterval !== void 0)
723
- this.scrollingJudgeInterval = convertedSetting.scrollingJudgeInterval;
724
- if (convertedSetting.baseAxis) this.baseAxis = convertedSetting.baseAxis;
725
- this._lastAxis = this.baseAxis;
726
- const { scrollSizeObserver } = convertedSetting;
727
- if (scrollSizeObserver) {
728
- this.scrollSizeObserver = {
729
- interval: 500,
730
- width: true,
731
- height: true,
732
- ...scrollSizeObserver
733
- };
734
- }
735
- this._visibilityListener = () => {
736
- if (visibilityManager.isVisible) {
737
- this.update();
738
- if (this._scrollSizeObserverSuspended) {
739
- this._scrollSizeObserverSuspended = false;
740
- this._startScrollSizeObserver();
741
- }
742
- } else {
743
- this._scrollSizeObserverSuspended = this._scrollSizeObserverPollingId !== null;
744
- this._stopScrollSizeObserver();
745
- }
746
- };
747
- this._lastDirection = this._lastAxis === "y" ? "top" : "left";
748
- if (!IN_WINDOW) return;
749
- visibilityManager.change(this._visibilityListener);
750
- this.setElement(convertedSetting.el);
751
- }
752
- /**
753
- * インスタンスにElementを設定します。特別な理由(SSRの利用等)によりコンストラクタでElementを指定できない場合、
754
- * 本メソッドを利用しブラウザコンテキスト配下で本メソッドを実行してください。
755
- * @param el - Element、もしくはCSSクエリセレクタ文字列を指定します。
756
- */
757
- setElement(el) {
758
- if (el === null) return;
759
- if (!IN_WINDOW)
760
- logger.error("Element can be set only when it is under DOM context.");
761
- this.stop();
762
- let _el;
763
- if (typeof el === "string") {
764
- _el = document.querySelector(el);
765
- } else {
766
- _el = el || document.scrollingElement;
767
- }
768
- if (!_el) {
769
- const message = "missing scrolling element";
770
- logger.error(message, el);
771
- throw new Error(message);
772
- }
773
- this._el = _el;
774
- this._isDocumentElement = isDocumentElement(_el);
775
- this._isBodyElement = isBodyElement(_el);
776
- this._isRootElement = this._isDocumentElement || this._isBodyElement;
777
- this._eventTarget = this._isDocumentElement || this._isBodyElement ? window : this._el;
778
- this._setup();
779
- }
780
- _scrollToElementAdditionalOffset;
781
- setScrollToElementAdditionalOffset(offset) {
782
- this._scrollToElementAdditionalOffset = offset;
783
- }
784
- deleteScrollToElementAdditionalOffset() {
785
- delete this._scrollToElementAdditionalOffset;
786
- }
787
- /**
788
- * インスタンスが実行可能になった際にresolveされるPromiseインスタンスを返却します。
789
- */
790
- ready() {
791
- this._checkDestroyed();
792
- if (!this.isPending) return Promise.resolve();
793
- return new Promise((resolve) => this._readyResolvers.push(resolve));
794
- }
795
- /**
796
- * インスタンスの動作を開始します。本インスタンスはElementが設定され初期化された際に自動で動作を開始しますが、
797
- * [[Scroller.stop]]メソッドを利用し動作を停止した後に再開する場合に本メソッドを利用します。
798
- */
799
- async start() {
800
- this._checkDestroyed();
801
- if (this.isRunning) return;
802
- await this.ready();
803
- this._startListeners();
804
- this._setState("running" /* Running */);
805
- }
806
- /**
807
- * インスタンスの動作(スクロール、リサイズイベントの検知等)を停止します。
808
- * 何らかの理由で動作を停止させたい場合に利用してください。
809
- * 本メソッドを実行後もインスタンス内の状態は保持されたままです。
810
- * 完全にインスタンスを破棄するためには[[Scroller.destroy]]を利用してください。
811
- */
812
- stop() {
813
- this._checkDestroyed();
814
- if (!this.isRunning) return;
815
- this._stopListeners();
816
- this._setState("ready" /* Ready */);
817
- }
818
- /**
819
- * インスタンスの動作を停止し、内部情報を完全に破棄します。
820
- * これに伴い、スクロール中であった場合にはキャンセルされ、以後イベント通知は完全に行われません。
821
- * また[[Scroller.start]]メソッドでの再利用も不可となります。
822
- * 本インスタンスの利用を完全に停止する場合に必ず実行し、利用側のオブジェクト等において本インスタンスへの参照を完全に削除してください。
823
- * 本メソッドはSPA等でのサービスにおいては意識的に実行する事を強く推奨します。
824
- */
825
- destroy() {
826
- if (this.isDestroyed) return;
827
- this.stop();
828
- this.cancel();
829
- this._readyResolvers = [];
830
- this._scrollStoppers = [];
831
- this._scrollEnable();
832
- this._observers = [];
833
- visibilityManager.remove(this._visibilityListener);
834
- delete this._el;
835
- delete this._eventTarget;
836
- delete this._scrollListener;
837
- delete this._resizeListener;
838
- delete this._resizeObserver;
839
- delete this._scrollToResult;
840
- delete this._visibilityListener;
841
- this.deleteScrollToElementAdditionalOffset();
842
- this._setState("destroyed" /* Destroyed */);
843
- this.offAll();
844
- }
845
- /**
846
- * インスタンス内部のスクロール量や、Elementのサイズを強制的に更新します。
847
- * 基本的に利用が必要なケースはありませんが、何らかの理由で更新をトリガーしたい場合に利用します。
848
- */
849
- update() {
850
- this._update();
851
- }
852
- /**
853
- * インスタンス内の情報をjsonオブジェクトとして返却します。
854
- * 情報の詳細は[[ScrollerObserver]]を参照してください。
855
- */
856
- toJSON() {
857
- const json = {};
858
- for (const key of scrollerObservableKeys) {
859
- json[key] = this[key];
860
- }
861
- return json;
862
- }
863
- /**
864
- * [[Scroller.toJSON]]の情報を文字列として返却します。
865
- */
866
- toString() {
867
- return JSON.stringify(this.toJSON());
868
- }
869
- /**
870
- * 本インスタンスの情報を購読するためのオブジェクトを設定する事で、
871
- * インスタンスの内部情報が変更される度にパラメータが同期されます。
872
- * 設定するオブジェクトは[[ScrollerObserver]]のインターフェースを満たしていれば内容は問いません。
873
- * 本機能により同期される方法は単純にオブジェクトプロパティへの変数代入です。
874
- * 従って対象となるプロパティをgetterとして実装(Ex: Vue computed等、、)しておく事により、
875
- * 同期を受け取るオブジェクト側でパラメータ変更後の動作をリアクティブに実装可能です。
876
- * @param observer - 同期させたいオブジェクト
877
- * @returns 同期を停止するためのメソッド
878
- */
879
- observe(observer) {
880
- if (!this._observers.includes(observer)) {
881
- this._observers.push(observer);
882
- }
883
- this._syncToObserver(observer);
884
- const unobserve = () => {
885
- this.unobserve(observer);
886
- };
887
- return unobserve;
888
- }
889
- /**
890
- * [[Scroller.observe]]でパラメータ同期中のオブジェクトを停止します。
891
- * [[Scroller.destroy]]実行時にも、同期中のオブジェクトは全停止されますが、destroy前に任意のタイミングで停止したい場合
892
- * 本メソッドを利用します。
893
- * @param observer - 同期中のオブジェクト
894
- */
895
- unobserve(observer) {
896
- const index = this._observers.indexOf(observer);
897
- if (index !== -1) {
898
- this._observers.splice(index, 1);
899
- }
900
- }
901
- /**
902
- * スクロール中であった場合、スクロールをキャンセルします。
903
- */
904
- cancel() {
905
- if (!this._scrollToResult) return;
906
- this._scrollToResult.cancel();
907
- this._clearScrollToResult();
908
- }
909
- /**
910
- * x, yの差分pxを指定しスクロールします。
911
- * メソッド、パラメータの詳細は[[scrollBy]]を参照してください。
912
- * @param diffX - 横移動量
913
- * @param diffY - 縦移動量
914
- * @param options - スクロールオプション
915
- */
916
- by(diffX, diffY, options) {
917
- return this._setScrollToResult(
918
- scrollBy(diffX, diffY, this._createMergedScrollOptions(options))
919
- );
920
- }
921
- /**
922
- * 指定の座標へスクロールします。
923
- * メソッド、パラメータの詳細は[[scrollTo]]を参照してください。
924
- * @param scrollPosition - 座標
925
- * @param options - スクロールオプション
926
- */
927
- to(scrollPosition, options) {
928
- return this._setScrollToResult(
929
- scrollTo(scrollPosition, this._createMergedScrollOptions(options))
930
- );
931
- }
932
- /**
933
- * 指定の要素の位置へスクロールします。
934
- * メソッド、パラメータの詳細は[[scrollToElement]]を参照してください。
935
- * オプションのx, yが未設定であった場合、[[Scroller.baseAxis]]により自動設定されます。
936
- * @param target - スクロール先の要素
937
- * @param options - スクロールオプション
938
- */
939
- toElement(target, options) {
940
- const merged = this._createMergedScrollToElementOptions(options);
941
- if (merged.x === void 0) merged.x = this.baseAxis === "x";
942
- if (merged.y === void 0) merged.y = this.baseAxis === "y";
943
- return this._setScrollToResult(scrollToElement(target, merged));
944
- }
945
- /**
946
- * 指定の辺へスクロールします。
947
- * メソッド、パラメータの詳細は[[scrollToSide]]を参照してください。
948
- * @param targets - スクロール先
949
- * @param options - スクロールオプション
950
- */
951
- toSide(targets, options) {
952
- return this._setScrollToResult(
953
- scrollToSide(targets, this._createMergedScrollOptions(options))
954
- );
955
- }
956
- /**
957
- * 上辺へスクロールします。
958
- * メソッド、パラメータの詳細は[[scrollToTop]]を参照してください。
959
- * @param options - スクロールオプション
960
- */
961
- toTop(options) {
962
- return this._setScrollToResult(
963
- scrollToTop(this._createMergedScrollOptions(options))
964
- );
965
- }
966
- /**
967
- * 右辺へスクロールします。
968
- * メソッド、パラメータの詳細は[[scrollToRight]]を参照してください。
969
- * @param options - スクロールオプション
970
- */
971
- toRight(options) {
972
- return this._setScrollToResult(
973
- scrollToRight(this._createMergedScrollOptions(options))
974
- );
975
- }
976
- /**
977
- * 下辺へスクロールします。
978
- * メソッド、パラメータの詳細は[[scrollToBottom]]を参照してください。
979
- * @param options - スクロールオプション
980
- */
981
- toBottom(options) {
982
- return this._setScrollToResult(
983
- scrollToBottom(this._createMergedScrollOptions(options))
984
- );
985
- }
986
- /**
987
- * 左辺へスクロールします。
988
- * メソッド、パラメータの詳細は[[scrollToLeft]]を参照してください。
989
- * @param options - スクロールオプション
990
- */
991
- toLeft(options) {
992
- return this._setScrollToResult(
993
- scrollToLeft(this._createMergedScrollOptions(options))
994
- );
995
- }
996
- /**
997
- * 左上コーナーへスクロールします。
998
- * メソッド、パラメータの詳細は[[scrollToLeftTop]]を参照してください。
999
- * @param options - スクロールオプション
1000
- */
1001
- toLeftTop(options) {
1002
- return this._setScrollToResult(
1003
- scrollToLeftTop(this._createMergedScrollOptions(options))
1004
- );
1005
- }
1006
- /**
1007
- * 左下コーナーへスクロールします。
1008
- * メソッド、パラメータの詳細は[[scrollToLeftBottom]]を参照してください。
1009
- * @param options - スクロールオプション
1010
- */
1011
- toLeftBottom(options) {
1012
- return this._setScrollToResult(
1013
- scrollToLeftBottom(this._createMergedScrollOptions(options))
1014
- );
1015
- }
1016
- /**
1017
- * 右上コーナーへスクロールします。
1018
- * メソッド、パラメータの詳細は[[scrollToRightTop]]を参照してください。
1019
- * @param options - スクロールオプション
1020
- */
1021
- toRightTop(options) {
1022
- return this._setScrollToResult(
1023
- scrollToRightTop(this._createMergedScrollOptions(options))
1024
- );
1025
- }
1026
- /**
1027
- * 右下コーナーへスクロールします。
1028
- * メソッド、パラメータの詳細は[[scrollToRightBottom]]を参照してください。
1029
- * @param options - スクロールオプション
1030
- */
1031
- toRightBottom(options) {
1032
- return this._setScrollToResult(
1033
- scrollToRightBottom(this._createMergedScrollOptions(options))
1034
- );
1035
- }
1036
- /**
1037
- * スクロールの停止を要求します。
1038
- * @param stopper - 停止要求ソース
1039
- */
1040
- pushScrollStopper(stopper) {
1041
- if (!this._scrollStoppers.includes(stopper)) {
1042
- this._scrollStoppers.push(stopper);
1043
- if (this._scrollStoppers.length === 1) {
1044
- this._updateScrollable();
1045
- this._syncToObservers(["scrollEnabled"]);
1046
- }
1047
- }
1048
- return () => {
1049
- this.removeScrollStopper(stopper);
1050
- };
1051
- }
1052
- /**
1053
- * スクロールの停止要求を解除します。<br>
1054
- * 別のプロセスにより異なる[[ScrollStopper]]が登録されている場合、
1055
- * スクロールは再開されない事に注意してください。
1056
- * @param stopper - 停止要求ソース
1057
- */
1058
- removeScrollStopper(stopper) {
1059
- const index = this._scrollStoppers.indexOf(stopper);
1060
- if (index !== -1) {
1061
- this._scrollStoppers.splice(index, 1);
1062
- if (this._scrollStoppers.length === 0) {
1063
- this._updateScrollable();
1064
- this._syncToObservers(["scrollEnabled"]);
1065
- }
1066
- }
1067
- }
1068
- async _setup() {
1069
- this._updateScrollable();
1070
- this._update();
1071
- this._setState("ready" /* Ready */);
1072
- this.start();
1073
- this.emit("ready", void 0);
1074
- this._readyResolvers.forEach((resolve) => resolve());
1075
- this._readyResolvers = [];
1076
- }
1077
- _setState(state) {
1078
- if (this._state !== state) {
1079
- this._state = state;
1080
- this._syncToObservers([
1081
- "state",
1082
- "isPending",
1083
- "isReady",
1084
- "isRunning",
1085
- "isDestroyed"
1086
- ]);
1087
- this.emit("changeState", state);
1088
- }
1089
- }
1090
- _checkDestroyed() {
1091
- if (this.isDestroyed) {
1092
- const message = "already destroyed.";
1093
- logger.error(message);
1094
- throw new Error(message);
1095
- }
1096
- }
1097
- _update(width, height) {
1098
- this._updateContainerSize(width, height);
1099
- this._updateScrollSize();
1100
- this._updateScrollPositions();
1101
- }
1102
- _updateContainerSize(width, height) {
1103
- const { el, _isBodyElement } = this;
1104
- if (width === void 0) {
1105
- if (!el) return;
1106
- width = _isBodyElement ? document.documentElement.clientWidth : el.clientWidth;
1107
- }
1108
- if (height === void 0) {
1109
- if (!el) return;
1110
- height = _isBodyElement ? document.documentElement.clientHeight : el.clientHeight;
1111
- }
1112
- const { _containerWidth, _containerHeight } = this;
1113
- this._containerWidth = width;
1114
- this._containerHeight = height;
1115
- if (width !== _containerWidth || height !== _containerHeight) {
1116
- this._syncToObservers([
1117
- "containerWidth",
1118
- "containerHeight",
1119
- "scrollableX",
1120
- "scrollableY"
1121
- ]);
1122
- this.emit("resize", { width, height });
1123
- }
1124
- }
1125
- _updateScrollSize() {
1126
- const { el, _scrollWidth, _scrollHeight } = this;
1127
- if (!el) return;
1128
- this._scrollWidth = el.scrollWidth;
1129
- this._scrollHeight = el.scrollHeight;
1130
- if (_scrollWidth !== this._scrollWidth || _scrollHeight !== this._scrollHeight) {
1131
- this._syncToObservers([
1132
- "scrollWidth",
1133
- "scrollHeight",
1134
- "scrollableX",
1135
- "scrollableY"
1136
- ]);
1137
- }
1138
- }
1139
- _startScrollSizeObserver() {
1140
- if (!IN_WINDOW) return;
1141
- this._stopScrollSizeObserver();
1142
- if (this.scrollSizeObserver) {
1143
- this._scrollSizeObserverPollingId = window.setInterval(() => {
1144
- if (!this.scrollSizeObserver || this.isDestroyed) {
1145
- this._stopScrollSizeObserver();
1146
- return;
1147
- }
1148
- this._updateScrollSize();
1149
- }, this.scrollSizeObserver.interval);
1150
- }
1151
- }
1152
- _stopScrollSizeObserver() {
1153
- if (this._scrollSizeObserverPollingId !== null) {
1154
- clearInterval(this._scrollSizeObserverPollingId);
1155
- this._scrollSizeObserverPollingId = null;
1156
- }
1157
- }
1158
- _updateScrollPositions() {
1159
- if (!this.el) return;
1160
- this._scrollTop = this.el.scrollTop;
1161
- this._scrollLeft = this.el.scrollLeft;
1162
- this._scrollBottom = this._scrollHeight - this._scrollTop - this._containerHeight;
1163
- this._scrollRight = this._scrollWidth - this._scrollLeft - this._containerWidth;
1164
- this._syncToObservers([
1165
- "scrollTop",
1166
- "scrollRight",
1167
- "scrollBottom",
1168
- "scrollLeft"
1169
- ]);
1170
- }
1171
- _startListeners() {
1172
- this._stopListeners();
1173
- this._scrollListener = () => {
1174
- this._onScroll();
1175
- };
1176
- this._eventTarget.addEventListener("scroll", this._scrollListener, false);
1177
- if (this._isRootElement) {
1178
- this._resizeListener = () => {
1179
- this._onResize();
1180
- };
1181
- window.addEventListener("resize", this._resizeListener, false);
1182
- } else {
1183
- this._resizeObserver = new ResizeObserver((entries) => {
1184
- for (const entry of entries) {
1185
- const { width, height } = entry.contentRect;
1186
- this._onResize(width, height);
1187
- }
1188
- });
1189
- this._el && this._resizeObserver.observe(this._el);
1190
- }
1191
- if (visibilityManager.isVisible) {
1192
- this._scrollSizeObserverSuspended = false;
1193
- this._startScrollSizeObserver();
1194
- } else {
1195
- this._scrollSizeObserverSuspended = true;
1196
- }
1197
- }
1198
- _stopListeners() {
1199
- if (this._scrollListener) {
1200
- this._eventTarget.removeEventListener(
1201
- "scroll",
1202
- this._scrollListener,
1203
- false
1204
- );
1205
- delete this._scrollListener;
1206
- }
1207
- if (this._resizeListener) {
1208
- if (this._isDocumentElement) {
1209
- window.removeEventListener("resize", this._resizeListener, false);
1210
- delete this._resizeListener;
1211
- }
1212
- }
1213
- if (this._resizeObserver && this._el) {
1214
- this._resizeObserver.unobserve(this._el);
1215
- this._resizeObserver.disconnect();
1216
- delete this._resizeObserver;
1217
- }
1218
- }
1219
- _clearScrollingJudgeTimer() {
1220
- if (this._scrollingJudgeTimerId !== null) {
1221
- clearTimeout(this._scrollingJudgeTimerId);
1222
- this._scrollingJudgeTimerId = null;
1223
- }
1224
- }
1225
- _onResize(width, height) {
1226
- this._update(width, height);
1227
- }
1228
- _triggerScrollTick(event) {
1229
- const { _nowScrolling } = this;
1230
- if (event === "scrollStart") {
1231
- this._startX = this._scrollLeft;
1232
- this._startY = this._scrollTop;
1233
- this._lastTotalX = 0;
1234
- this._lastTotalY = 0;
1235
- this._nowScrolling = true;
1236
- } else if (event === "scrollEnd") {
1237
- this._nowScrolling = false;
1238
- }
1239
- if (_nowScrolling !== this._nowScrolling) {
1240
- this._syncToObservers("nowScrolling");
1241
- }
1242
- this.emit(event, this.lastPayload);
1243
- }
1244
- _onScroll() {
1245
- if (!this.scrollEnabled && this._el) {
1246
- this._el.scrollLeft = this._scrollLeft;
1247
- this._el.scrollTop = this._scrollTop;
1248
- return;
1249
- }
1250
- const {
1251
- _scrollTop,
1252
- _scrollLeft,
1253
- _lastAxis,
1254
- _lastDirection,
1255
- _lastXDirection,
1256
- _lastYDirection
1257
- } = this;
1258
- this._updateScrollPositions();
1259
- const tickedX = this._scrollLeft - _scrollLeft;
1260
- const tickedY = this._scrollTop - _scrollTop;
1261
- this._tickedX = tickedX;
1262
- this._tickedY = tickedY;
1263
- if (tickedX === tickedY) {
1264
- this._lastAxis = this.baseAxis;
1265
- } else {
1266
- this._lastAxis = Math.abs(tickedX) > Math.abs(tickedY) ? "x" : "y";
1267
- }
1268
- if (_scrollTop < this._scrollTop) {
1269
- this._lastYDirection = "bottom";
1270
- } else if (_scrollTop > this._scrollTop) {
1271
- this._lastYDirection = "top";
1272
- }
1273
- if (_scrollLeft < this._scrollLeft) {
1274
- this._lastXDirection = "right";
1275
- } else if (_scrollLeft > this._scrollLeft) {
1276
- this._lastXDirection = "left";
1277
- }
1278
- this._lastDirection = this._lastAxis === "y" ? this._lastYDirection : this._lastXDirection;
1279
- const axisIsChanged = this._lastAxis !== _lastAxis;
1280
- const lastXDirectionIsChanged = this._lastXDirection !== _lastXDirection;
1281
- const lastYDirectionIsChanged = this._lastYDirection !== _lastYDirection;
1282
- const lastDirectionIsChanged = this._lastDirection !== _lastDirection;
1283
- if (axisIsChanged) {
1284
- this.emit("changeAxis", this._lastAxis);
1285
- }
1286
- if (lastXDirectionIsChanged) {
1287
- this.emit("changeLastXDirection", this._lastXDirection);
1288
- }
1289
- if (lastYDirectionIsChanged) {
1290
- this.emit("changeLastYDirection", this._lastYDirection);
1291
- }
1292
- if (lastDirectionIsChanged) {
1293
- this.emit("changeLastDirection", this._lastDirection);
1294
- }
1295
- if (axisIsChanged || lastXDirectionIsChanged || lastYDirectionIsChanged || lastDirectionIsChanged) {
1296
- this._syncToObservers([
1297
- "lastAxis",
1298
- "lastDirection",
1299
- "lastYDirection",
1300
- "lastXDirection"
1301
- ]);
1302
- }
1303
- if (this._nowScrolling) {
1304
- if (axisIsChanged || _lastAxis === "y" && lastYDirectionIsChanged || _lastAxis === "x" && lastXDirectionIsChanged) {
1305
- this._triggerScrollTick("scrollEnd");
1306
- } else {
1307
- this._lastTotalX = this._scrollLeft - this._startX;
1308
- this._lastTotalY = this._scrollTop - this._startY;
1309
- this._triggerScrollTick("scroll");
1310
- }
1311
- }
1312
- if (!this._nowScrolling) {
1313
- this._updateScrollSize();
1314
- this._triggerScrollTick("scrollStart");
1315
- }
1316
- this._clearScrollingJudgeTimer();
1317
- this._scrollingJudgeTimerId = window.setTimeout(() => {
1318
- this._triggerScrollTick("scrollEnd");
1319
- }, this.scrollingJudgeInterval);
1320
- }
1321
- _syncToObserver(observer, keys = scrollerObservableKeys) {
1322
- for (const key of keys) {
1323
- observer[key] = this[key];
1324
- }
1325
- }
1326
- _syncToObservers(keys) {
1327
- if (this._observers.length === 0) return;
1328
- keys = typeof keys === "string" ? [keys] : keys;
1329
- for (const observer of this._observers) {
1330
- this._syncToObserver(observer, keys);
1331
- }
1332
- }
1333
- _checkElement() {
1334
- const { _el } = this;
1335
- if (!_el) {
1336
- const message = "missing element";
1337
- logger.error(message);
1338
- throw new Error(message);
1339
- }
1340
- return _el;
1341
- }
1342
- _createMergedScrollOptions(source) {
1343
- const el = this._checkElement();
1344
- const merged = {
1345
- container: el,
1346
- ...this.scrollSettingsDefaults,
1347
- ...source
1348
- };
1349
- return merged;
1350
- }
1351
- _createMergedScrollToElementOptions(source) {
1352
- const el = this._checkElement();
1353
- const merged = {
1354
- container: el,
1355
- ...this.scrollToElementSettingsDefaults,
1356
- ...source
1357
- };
1358
- let { _scrollToElementAdditionalOffset: additionalOffset } = this;
1359
- if (!additionalOffset) return merged;
1360
- if (typeof additionalOffset === "function") {
1361
- additionalOffset = additionalOffset(this);
1362
- }
1363
- if (!additionalOffset) return merged;
1364
- if (typeof additionalOffset === "number") {
1365
- additionalOffset = {
1366
- x: additionalOffset,
1367
- y: additionalOffset
1368
- };
1369
- }
1370
- let { offset } = merged;
1371
- if (!offset) {
1372
- merged.offset = additionalOffset;
1373
- return merged;
1374
- }
1375
- if (typeof offset === "number") {
1376
- offset = {
1377
- x: offset,
1378
- y: offset
1379
- };
1380
- }
1381
- offset.x = (offset.x || 0) + (additionalOffset.x || 0);
1382
- offset.y = (offset.y || 0) + (additionalOffset.y || 0);
1383
- merged.offset = offset;
1384
- return merged;
1385
- }
1386
- _clearScrollToResult() {
1387
- if (!this._scrollToResult) return;
1388
- this._scrollToResult = null;
1389
- }
1390
- _setScrollToResult(result) {
1391
- this._scrollToResult = result;
1392
- result.promise.then(() => {
1393
- this._clearScrollToResult();
1394
- });
1395
- return result;
1396
- }
1397
- _updateScrollable() {
1398
- if (this.scrollEnabled) {
1399
- this._scrollEnable();
1400
- } else {
1401
- this._scrollDisable();
1402
- }
1403
- }
1404
- _scrollEnable() {
1405
- enableScroll(this._checkElement());
1406
- }
1407
- _scrollDisable() {
1408
- const el = this._checkElement();
1409
- this.cancel();
1410
- disableScroll(el);
1411
- }
540
+ /**
541
+ * Scrollerクラスの状態を監視&同期するオブジェクトが
542
+ * 保有すべきプロパティ一のキーの配列です。
543
+ */
544
+ static scrollerObservableKeys = scrollerObservableKeys;
545
+ /**
546
+ * Scrollerの状態を示すenum値です。
547
+ * {@link ScrollerState}
548
+ */
549
+ static States = ScrollerState;
550
+ /**
551
+ * スクロールを検知してから、移動がなくなった際に、何ms後にスクロール終了と判定するかのインターバル値を示します。
552
+ * デフォルトは500です。
553
+ */
554
+ scrollingJudgeInterval = 500;
555
+ /**
556
+ * 縦、横のどちらのスクロールを基準とするかを示します。
557
+ * デフォルトはyです。<br>
558
+ * この設定は[[Scroller.toElement]]のデフォルト値にも影響します。
559
+ */
560
+ baseAxis = "y";
561
+ /**
562
+ * スクロール系メソッド[[Scroller.to]]等を利用する際のデフォルトの設定を示します。
563
+ */
564
+ scrollSettingsDefaults = { ...defaultBaseSettings };
565
+ /**
566
+ * [[Scroller.toElement]]のデフォルトオプションの設定を示します。
567
+ */
568
+ scrollToElementSettingsDefaults = { ...scrollToElementSettingsDefaults };
569
+ scrollSizeObserver;
570
+ /**
571
+ * 設定されたElement要素です。
572
+ * 初期化が完了していない時には本getterはundefinedを返却する事に注意してください。
573
+ */
574
+ get el() {
575
+ return this._el;
576
+ }
577
+ /**
578
+ * 現在の状態です。<br>
579
+ * {@link ScrollerState}
580
+ */
581
+ get state() {
582
+ return this._state;
583
+ }
584
+ /**
585
+ * 未初期化である場合trueを示します。
586
+ */
587
+ get isPending() {
588
+ return this._state === "pending";
589
+ }
590
+ /**
591
+ * 初期化済み&停止状態である場合trueを示します。
592
+ */
593
+ get isReady() {
594
+ return this._state === "ready";
595
+ }
596
+ /**
597
+ * 初期化済み&動作中である場合trueを示します。
598
+ */
599
+ get isRunning() {
600
+ return this._state === "running";
601
+ }
602
+ /**
603
+ * インスタンスが破棄済みである場合trueを示します。
604
+ */
605
+ get isDestroyed() {
606
+ return this._state === "destroyed";
607
+ }
608
+ /**
609
+ * スクロールの有効状態を取得します
610
+ */
611
+ get scrollEnabled() {
612
+ return this._scrollStoppers.length === 0;
613
+ }
614
+ /**
615
+ * スクロール要素の幅を示します。
616
+ */
617
+ get containerWidth() {
618
+ return this._containerWidth;
619
+ }
620
+ /**
621
+ * スクロール要素の高さを示します。
622
+ */
623
+ get containerHeight() {
624
+ return this._containerHeight;
625
+ }
626
+ /**
627
+ * スクロール要素内のコンテンツの幅を示します。
628
+ */
629
+ get scrollWidth() {
630
+ return this._scrollWidth;
631
+ }
632
+ /**
633
+ * スクロール要素内のコンテンツの高さを示します。
634
+ */
635
+ get scrollHeight() {
636
+ return this._scrollHeight;
637
+ }
638
+ /**
639
+ * x軸にスクロール可能な場合trueを示します
640
+ */
641
+ get scrollableX() {
642
+ return this._scrollWidth > this._containerWidth;
643
+ }
644
+ /**
645
+ * y軸にスクロール可能な場合trueを示します
646
+ */
647
+ get scrollableY() {
648
+ return this._scrollHeight > this._containerHeight;
649
+ }
650
+ /**
651
+ * 現在の上辺からのスクロール量を示します。
652
+ */
653
+ get scrollTop() {
654
+ return this._scrollTop;
655
+ }
656
+ set scrollTop(scrollTop) {
657
+ if (!this.el) return;
658
+ this.el.scrollTop = scrollTop;
659
+ }
660
+ /**
661
+ * 現在の右辺からのスクロール量を示します。
662
+ */
663
+ get scrollRight() {
664
+ return this._scrollRight;
665
+ }
666
+ set scrollRight(scrollRight) {
667
+ if (!this.el) return;
668
+ this.el.scrollLeft = this._scrollWidth - this._containerWidth - scrollRight;
669
+ }
670
+ /**
671
+ * 現在の下辺からのスクロール量を示します。
672
+ */
673
+ get scrollBottom() {
674
+ return this._scrollBottom;
675
+ }
676
+ set scrollBottom(scrollBottom) {
677
+ if (!this.el) return;
678
+ this.el.scrollTop = this._scrollHeight - this._containerHeight - scrollBottom;
679
+ }
680
+ /**
681
+ * 現在の左辺からのスクロール量を示します。
682
+ */
683
+ get scrollLeft() {
684
+ return this._scrollLeft;
685
+ }
686
+ set scrollLeft(scrollLeft) {
687
+ if (!this.el) return;
688
+ this.el.scrollLeft = scrollLeft;
689
+ }
690
+ /**
691
+ * 現在スクロール中である場合trueを示します。
692
+ */
693
+ get nowScrolling() {
694
+ return this._nowScrolling;
695
+ }
696
+ /**
697
+ * 最後に検知したスクロールの軸を示します。
698
+ */
699
+ get lastAxis() {
700
+ return this._lastAxis;
701
+ }
702
+ /**
703
+ * 最後に検知したスクロールの方向を示します。
704
+ */
705
+ get lastDirection() {
706
+ return this._lastDirection;
707
+ }
708
+ /**
709
+ * 最後に検知したスクロールの垂直方向を示します。
710
+ */
711
+ get lastYDirection() {
712
+ return this._lastYDirection;
713
+ }
714
+ /**
715
+ * 最後に検知したスクロールの水平方向を示します。
716
+ */
717
+ get lastXDirection() {
718
+ return this._lastXDirection;
719
+ }
720
+ /**
721
+ * 最後に検知したスクロールにより通知した情報を示します。
722
+ */
723
+ get lastPayload() {
724
+ return {
725
+ top: this._scrollTop,
726
+ left: this._scrollLeft,
727
+ bottom: this._scrollBottom,
728
+ right: this._scrollRight,
729
+ axis: this._lastAxis,
730
+ direction: this._lastDirection,
731
+ directionX: this._lastXDirection,
732
+ directionY: this._lastYDirection,
733
+ tickedX: this._tickedX,
734
+ tickedY: this._tickedY,
735
+ totalX: this._lastTotalX,
736
+ totalY: this._lastTotalY
737
+ };
738
+ }
739
+ _el;
740
+ _eventTarget;
741
+ _isDocumentElement = false;
742
+ _isBodyElement = false;
743
+ _isRootElement = false;
744
+ _state = "pending";
745
+ _containerWidth = 0;
746
+ _containerHeight = 0;
747
+ _scrollWidth = 0;
748
+ _scrollHeight = 0;
749
+ _scrollTop = 0;
750
+ _scrollRight = 0;
751
+ _scrollBottom = 0;
752
+ _scrollLeft = 0;
753
+ _lastAxis;
754
+ _lastDirection;
755
+ _lastYDirection = "top";
756
+ _lastXDirection = "left";
757
+ _nowScrolling = false;
758
+ _readyResolvers = [];
759
+ _scrollingJudgeTimerId = null;
760
+ _startX = 0;
761
+ _startY = 0;
762
+ _tickedX = 0;
763
+ _tickedY = 0;
764
+ _lastTotalX = 0;
765
+ _lastTotalY = 0;
766
+ _scrollListener;
767
+ _resizeListener;
768
+ _resizeObserver;
769
+ _scrollToResult = null;
770
+ _observers = [];
771
+ _scrollStoppers = [];
772
+ _scrollSizeObserverPollingId = null;
773
+ _scrollSizeObserverSuspended = false;
774
+ _visibilityListener;
775
+ /**
776
+ * Scrollerインスタンスを作成します。
777
+ * コンテキストとなるElementをこの時点で指定するか否かは任意です。
778
+ *
779
+ * @param settingOrElementOrQueryString - 任意です。{@link ScrollerSetting}か Element(or cssクエリセレクタ文字列)を直接指定します。この時点でElementを指定しない場合は、[[setElement]]を実行するまでインスタンスは動作しません。
780
+ */
781
+ constructor(settingOrElementOrQueryString = {}) {
782
+ super();
783
+ const convertedSetting = typeof settingOrElementOrQueryString === "string" || settingOrElementOrQueryString === null || IN_WINDOW && settingOrElementOrQueryString instanceof Element ? settingOrElementOrQueryString = { el: settingOrElementOrQueryString } : settingOrElementOrQueryString;
784
+ if (convertedSetting.scrollingJudgeInterval !== void 0) this.scrollingJudgeInterval = convertedSetting.scrollingJudgeInterval;
785
+ if (convertedSetting.baseAxis) this.baseAxis = convertedSetting.baseAxis;
786
+ this._lastAxis = this.baseAxis;
787
+ const { scrollSizeObserver } = convertedSetting;
788
+ if (scrollSizeObserver) this.scrollSizeObserver = {
789
+ interval: 500,
790
+ width: true,
791
+ height: true,
792
+ ...scrollSizeObserver
793
+ };
794
+ this._visibilityListener = () => {
795
+ if (visibilityManager.isVisible) {
796
+ this.update();
797
+ if (this._scrollSizeObserverSuspended) {
798
+ this._scrollSizeObserverSuspended = false;
799
+ this._startScrollSizeObserver();
800
+ }
801
+ } else {
802
+ this._scrollSizeObserverSuspended = this._scrollSizeObserverPollingId !== null;
803
+ this._stopScrollSizeObserver();
804
+ }
805
+ };
806
+ this._lastDirection = this._lastAxis === "y" ? "top" : "left";
807
+ if (!IN_WINDOW) return;
808
+ visibilityManager.change(this._visibilityListener);
809
+ this.setElement(convertedSetting.el);
810
+ }
811
+ /**
812
+ * インスタンスにElementを設定します。特別な理由(SSRの利用等)によりコンストラクタでElementを指定できない場合、
813
+ * 本メソッドを利用しブラウザコンテキスト配下で本メソッドを実行してください。
814
+ * @param el - Element、もしくはCSSクエリセレクタ文字列を指定します。
815
+ */
816
+ setElement(el) {
817
+ if (el === null) return;
818
+ if (!IN_WINDOW) logger.error("Element can be set only when it is under DOM context.");
819
+ this.stop();
820
+ let _el;
821
+ if (typeof el === "string") _el = document.querySelector(el);
822
+ else _el = el || document.scrollingElement;
823
+ if (!_el) {
824
+ const message = "missing scrolling element";
825
+ logger.error(message, el);
826
+ throw new Error(message);
827
+ }
828
+ this._el = _el;
829
+ this._isDocumentElement = isDocumentElement(_el);
830
+ this._isBodyElement = isBodyElement$1(_el);
831
+ this._isRootElement = this._isDocumentElement || this._isBodyElement;
832
+ this._eventTarget = this._isDocumentElement || this._isBodyElement ? window : this._el;
833
+ this._setup();
834
+ }
835
+ _scrollToElementAdditionalOffset;
836
+ setScrollToElementAdditionalOffset(offset) {
837
+ this._scrollToElementAdditionalOffset = offset;
838
+ }
839
+ deleteScrollToElementAdditionalOffset() {
840
+ delete this._scrollToElementAdditionalOffset;
841
+ }
842
+ /**
843
+ * インスタンスが実行可能になった際にresolveされるPromiseインスタンスを返却します。
844
+ */
845
+ ready() {
846
+ this._checkDestroyed();
847
+ if (!this.isPending) return Promise.resolve();
848
+ return new Promise((resolve) => this._readyResolvers.push(resolve));
849
+ }
850
+ /**
851
+ * インスタンスの動作を開始します。本インスタンスはElementが設定され初期化された際に自動で動作を開始しますが、
852
+ * [[Scroller.stop]]メソッドを利用し動作を停止した後に再開する場合に本メソッドを利用します。
853
+ */
854
+ async start() {
855
+ this._checkDestroyed();
856
+ if (this.isRunning) return;
857
+ await this.ready();
858
+ this._startListeners();
859
+ this._setState("running");
860
+ }
861
+ /**
862
+ * インスタンスの動作(スクロール、リサイズイベントの検知等)を停止します。
863
+ * 何らかの理由で動作を停止させたい場合に利用してください。
864
+ * 本メソッドを実行後もインスタンス内の状態は保持されたままです。
865
+ * 完全にインスタンスを破棄するためには[[Scroller.destroy]]を利用してください。
866
+ */
867
+ stop() {
868
+ this._checkDestroyed();
869
+ if (!this.isRunning) return;
870
+ this._stopListeners();
871
+ this._setState("ready");
872
+ }
873
+ /**
874
+ * インスタンスの動作を停止し、内部情報を完全に破棄します。
875
+ * これに伴い、スクロール中であった場合にはキャンセルされ、以後イベント通知は完全に行われません。
876
+ * また[[Scroller.start]]メソッドでの再利用も不可となります。
877
+ * 本インスタンスの利用を完全に停止する場合に必ず実行し、利用側のオブジェクト等において本インスタンスへの参照を完全に削除してください。
878
+ * 本メソッドはSPA等でのサービスにおいては意識的に実行する事を強く推奨します。
879
+ */
880
+ destroy() {
881
+ if (this.isDestroyed) return;
882
+ this.stop();
883
+ this.cancel();
884
+ this._readyResolvers = [];
885
+ this._scrollStoppers = [];
886
+ this._scrollEnable();
887
+ this._observers = [];
888
+ visibilityManager.remove(this._visibilityListener);
889
+ delete this._el;
890
+ delete this._eventTarget;
891
+ delete this._scrollListener;
892
+ delete this._resizeListener;
893
+ delete this._resizeObserver;
894
+ delete this._scrollToResult;
895
+ delete this._visibilityListener;
896
+ this.deleteScrollToElementAdditionalOffset();
897
+ this._setState("destroyed");
898
+ this.offAll();
899
+ }
900
+ /**
901
+ * インスタンス内部のスクロール量や、Elementのサイズを強制的に更新します。
902
+ * 基本的に利用が必要なケースはありませんが、何らかの理由で更新をトリガーしたい場合に利用します。
903
+ */
904
+ update() {
905
+ this._update();
906
+ }
907
+ /**
908
+ * インスタンス内の情報をjsonオブジェクトとして返却します。
909
+ * 情報の詳細は[[ScrollerObserver]]を参照してください。
910
+ */
911
+ toJSON() {
912
+ const json = {};
913
+ for (const key of scrollerObservableKeys) json[key] = this[key];
914
+ return json;
915
+ }
916
+ /**
917
+ * [[Scroller.toJSON]]の情報を文字列として返却します。
918
+ */
919
+ toString() {
920
+ return JSON.stringify(this.toJSON());
921
+ }
922
+ /**
923
+ * 本インスタンスの情報を購読するためのオブジェクトを設定する事で、
924
+ * インスタンスの内部情報が変更される度にパラメータが同期されます。
925
+ * 設定するオブジェクトは[[ScrollerObserver]]のインターフェースを満たしていれば内容は問いません。
926
+ * 本機能により同期される方法は単純にオブジェクトプロパティへの変数代入です。
927
+ * 従って対象となるプロパティをgetterとして実装(Ex: Vue computed等、、)しておく事により、
928
+ * 同期を受け取るオブジェクト側でパラメータ変更後の動作をリアクティブに実装可能です。
929
+ * @param observer - 同期させたいオブジェクト
930
+ * @returns 同期を停止するためのメソッド
931
+ */
932
+ observe(observer) {
933
+ if (!this._observers.includes(observer)) this._observers.push(observer);
934
+ this._syncToObserver(observer);
935
+ const unobserve = () => {
936
+ this.unobserve(observer);
937
+ };
938
+ return unobserve;
939
+ }
940
+ /**
941
+ * [[Scroller.observe]]でパラメータ同期中のオブジェクトを停止します。
942
+ * [[Scroller.destroy]]実行時にも、同期中のオブジェクトは全停止されますが、destroy前に任意のタイミングで停止したい場合
943
+ * 本メソッドを利用します。
944
+ * @param observer - 同期中のオブジェクト
945
+ */
946
+ unobserve(observer) {
947
+ const index = this._observers.indexOf(observer);
948
+ if (index !== -1) this._observers.splice(index, 1);
949
+ }
950
+ /**
951
+ * スクロール中であった場合、スクロールをキャンセルします。
952
+ */
953
+ cancel() {
954
+ if (!this._scrollToResult) return;
955
+ this._scrollToResult.cancel();
956
+ this._clearScrollToResult();
957
+ }
958
+ /**
959
+ * x, yの差分pxを指定しスクロールします。
960
+ * メソッド、パラメータの詳細は[[scrollBy]]を参照してください。
961
+ * @param diffX - 横移動量
962
+ * @param diffY - 縦移動量
963
+ * @param options - スクロールオプション
964
+ */
965
+ by(diffX, diffY, options) {
966
+ return this._setScrollToResult(scrollBy(diffX, diffY, this._createMergedScrollOptions(options)));
967
+ }
968
+ /**
969
+ * 指定の座標へスクロールします。
970
+ * メソッド、パラメータの詳細は[[scrollTo]]を参照してください。
971
+ * @param scrollPosition - 座標
972
+ * @param options - スクロールオプション
973
+ */
974
+ to(scrollPosition, options) {
975
+ return this._setScrollToResult(scrollTo(scrollPosition, this._createMergedScrollOptions(options)));
976
+ }
977
+ /**
978
+ * 指定の要素の位置へスクロールします。
979
+ * メソッド、パラメータの詳細は[[scrollToElement]]を参照してください。
980
+ * オプションのx, yが未設定であった場合、[[Scroller.baseAxis]]により自動設定されます。
981
+ * @param target - スクロール先の要素
982
+ * @param options - スクロールオプション
983
+ */
984
+ toElement(target, options) {
985
+ const merged = this._createMergedScrollToElementOptions(options);
986
+ if (merged.x === void 0) merged.x = this.baseAxis === "x";
987
+ if (merged.y === void 0) merged.y = this.baseAxis === "y";
988
+ return this._setScrollToResult(scrollToElement(target, merged));
989
+ }
990
+ /**
991
+ * 指定の辺へスクロールします。
992
+ * メソッド、パラメータの詳細は[[scrollToSide]]を参照してください。
993
+ * @param targets - スクロール先
994
+ * @param options - スクロールオプション
995
+ */
996
+ toSide(targets, options) {
997
+ return this._setScrollToResult(scrollToSide(targets, this._createMergedScrollOptions(options)));
998
+ }
999
+ /**
1000
+ * 上辺へスクロールします。
1001
+ * メソッド、パラメータの詳細は[[scrollToTop]]を参照してください。
1002
+ * @param options - スクロールオプション
1003
+ */
1004
+ toTop(options) {
1005
+ return this._setScrollToResult(scrollToTop(this._createMergedScrollOptions(options)));
1006
+ }
1007
+ /**
1008
+ * 右辺へスクロールします。
1009
+ * メソッド、パラメータの詳細は[[scrollToRight]]を参照してください。
1010
+ * @param options - スクロールオプション
1011
+ */
1012
+ toRight(options) {
1013
+ return this._setScrollToResult(scrollToRight(this._createMergedScrollOptions(options)));
1014
+ }
1015
+ /**
1016
+ * 下辺へスクロールします。
1017
+ * メソッド、パラメータの詳細は[[scrollToBottom]]を参照してください。
1018
+ * @param options - スクロールオプション
1019
+ */
1020
+ toBottom(options) {
1021
+ return this._setScrollToResult(scrollToBottom(this._createMergedScrollOptions(options)));
1022
+ }
1023
+ /**
1024
+ * 左辺へスクロールします。
1025
+ * メソッド、パラメータの詳細は[[scrollToLeft]]を参照してください。
1026
+ * @param options - スクロールオプション
1027
+ */
1028
+ toLeft(options) {
1029
+ return this._setScrollToResult(scrollToLeft(this._createMergedScrollOptions(options)));
1030
+ }
1031
+ /**
1032
+ * 左上コーナーへスクロールします。
1033
+ * メソッド、パラメータの詳細は[[scrollToLeftTop]]を参照してください。
1034
+ * @param options - スクロールオプション
1035
+ */
1036
+ toLeftTop(options) {
1037
+ return this._setScrollToResult(scrollToLeftTop(this._createMergedScrollOptions(options)));
1038
+ }
1039
+ /**
1040
+ * 左下コーナーへスクロールします。
1041
+ * メソッド、パラメータの詳細は[[scrollToLeftBottom]]を参照してください。
1042
+ * @param options - スクロールオプション
1043
+ */
1044
+ toLeftBottom(options) {
1045
+ return this._setScrollToResult(scrollToLeftBottom(this._createMergedScrollOptions(options)));
1046
+ }
1047
+ /**
1048
+ * 右上コーナーへスクロールします。
1049
+ * メソッド、パラメータの詳細は[[scrollToRightTop]]を参照してください。
1050
+ * @param options - スクロールオプション
1051
+ */
1052
+ toRightTop(options) {
1053
+ return this._setScrollToResult(scrollToRightTop(this._createMergedScrollOptions(options)));
1054
+ }
1055
+ /**
1056
+ * 右下コーナーへスクロールします。
1057
+ * メソッド、パラメータの詳細は[[scrollToRightBottom]]を参照してください。
1058
+ * @param options - スクロールオプション
1059
+ */
1060
+ toRightBottom(options) {
1061
+ return this._setScrollToResult(scrollToRightBottom(this._createMergedScrollOptions(options)));
1062
+ }
1063
+ /**
1064
+ * スクロールの停止を要求します。
1065
+ * @param stopper - 停止要求ソース
1066
+ */
1067
+ pushScrollStopper(stopper) {
1068
+ if (!this._scrollStoppers.includes(stopper)) {
1069
+ this._scrollStoppers.push(stopper);
1070
+ if (this._scrollStoppers.length === 1) {
1071
+ this._updateScrollable();
1072
+ this._syncToObservers(["scrollEnabled"]);
1073
+ }
1074
+ }
1075
+ return () => {
1076
+ this.removeScrollStopper(stopper);
1077
+ };
1078
+ }
1079
+ /**
1080
+ * スクロールの停止要求を解除します。<br>
1081
+ * 別のプロセスにより異なる[[ScrollStopper]]が登録されている場合、
1082
+ * スクロールは再開されない事に注意してください。
1083
+ * @param stopper - 停止要求ソース
1084
+ */
1085
+ removeScrollStopper(stopper) {
1086
+ const index = this._scrollStoppers.indexOf(stopper);
1087
+ if (index !== -1) {
1088
+ this._scrollStoppers.splice(index, 1);
1089
+ if (this._scrollStoppers.length === 0) {
1090
+ this._updateScrollable();
1091
+ this._syncToObservers(["scrollEnabled"]);
1092
+ }
1093
+ }
1094
+ }
1095
+ async _setup() {
1096
+ this._updateScrollable();
1097
+ this._update();
1098
+ this._setState("ready");
1099
+ this.start();
1100
+ this.emit("ready", void 0);
1101
+ this._readyResolvers.forEach((resolve) => resolve());
1102
+ this._readyResolvers = [];
1103
+ }
1104
+ _setState(state) {
1105
+ if (this._state !== state) {
1106
+ this._state = state;
1107
+ this._syncToObservers([
1108
+ "state",
1109
+ "isPending",
1110
+ "isReady",
1111
+ "isRunning",
1112
+ "isDestroyed"
1113
+ ]);
1114
+ this.emit("changeState", state);
1115
+ }
1116
+ }
1117
+ _checkDestroyed() {
1118
+ if (this.isDestroyed) {
1119
+ const message = "already destroyed.";
1120
+ logger.error(message);
1121
+ throw new Error(message);
1122
+ }
1123
+ }
1124
+ _update(width, height) {
1125
+ this._updateContainerSize(width, height);
1126
+ this._updateScrollSize();
1127
+ this._updateScrollPositions();
1128
+ }
1129
+ _updateContainerSize(width, height) {
1130
+ const { el, _isBodyElement } = this;
1131
+ if (width === void 0) {
1132
+ if (!el) return;
1133
+ width = _isBodyElement ? document.documentElement.clientWidth : el.clientWidth;
1134
+ }
1135
+ if (height === void 0) {
1136
+ if (!el) return;
1137
+ height = _isBodyElement ? document.documentElement.clientHeight : el.clientHeight;
1138
+ }
1139
+ const { _containerWidth, _containerHeight } = this;
1140
+ this._containerWidth = width;
1141
+ this._containerHeight = height;
1142
+ if (width !== _containerWidth || height !== _containerHeight) {
1143
+ this._syncToObservers([
1144
+ "containerWidth",
1145
+ "containerHeight",
1146
+ "scrollableX",
1147
+ "scrollableY"
1148
+ ]);
1149
+ this.emit("resize", {
1150
+ width,
1151
+ height
1152
+ });
1153
+ }
1154
+ }
1155
+ _updateScrollSize() {
1156
+ const { el, _scrollWidth, _scrollHeight } = this;
1157
+ if (!el) return;
1158
+ this._scrollWidth = el.scrollWidth;
1159
+ this._scrollHeight = el.scrollHeight;
1160
+ if (_scrollWidth !== this._scrollWidth || _scrollHeight !== this._scrollHeight) this._syncToObservers([
1161
+ "scrollWidth",
1162
+ "scrollHeight",
1163
+ "scrollableX",
1164
+ "scrollableY"
1165
+ ]);
1166
+ }
1167
+ _startScrollSizeObserver() {
1168
+ if (!IN_WINDOW) return;
1169
+ this._stopScrollSizeObserver();
1170
+ if (this.scrollSizeObserver) this._scrollSizeObserverPollingId = window.setInterval(() => {
1171
+ if (!this.scrollSizeObserver || this.isDestroyed) {
1172
+ this._stopScrollSizeObserver();
1173
+ return;
1174
+ }
1175
+ this._updateScrollSize();
1176
+ }, this.scrollSizeObserver.interval);
1177
+ }
1178
+ _stopScrollSizeObserver() {
1179
+ if (this._scrollSizeObserverPollingId !== null) {
1180
+ clearInterval(this._scrollSizeObserverPollingId);
1181
+ this._scrollSizeObserverPollingId = null;
1182
+ }
1183
+ }
1184
+ _updateScrollPositions() {
1185
+ if (!this.el) return;
1186
+ this._scrollTop = this.el.scrollTop;
1187
+ this._scrollLeft = this.el.scrollLeft;
1188
+ this._scrollBottom = this._scrollHeight - this._scrollTop - this._containerHeight;
1189
+ this._scrollRight = this._scrollWidth - this._scrollLeft - this._containerWidth;
1190
+ this._syncToObservers([
1191
+ "scrollTop",
1192
+ "scrollRight",
1193
+ "scrollBottom",
1194
+ "scrollLeft"
1195
+ ]);
1196
+ }
1197
+ _startListeners() {
1198
+ this._stopListeners();
1199
+ this._scrollListener = () => {
1200
+ this._onScroll();
1201
+ };
1202
+ this._eventTarget.addEventListener("scroll", this._scrollListener, false);
1203
+ if (this._isRootElement) {
1204
+ this._resizeListener = () => {
1205
+ this._onResize();
1206
+ };
1207
+ window.addEventListener("resize", this._resizeListener, false);
1208
+ } else {
1209
+ this._resizeObserver = new ResizeObserver((entries) => {
1210
+ for (const entry of entries) {
1211
+ const { width, height } = entry.contentRect;
1212
+ this._onResize(width, height);
1213
+ }
1214
+ });
1215
+ this._el && this._resizeObserver.observe(this._el);
1216
+ }
1217
+ if (visibilityManager.isVisible) {
1218
+ this._scrollSizeObserverSuspended = false;
1219
+ this._startScrollSizeObserver();
1220
+ } else this._scrollSizeObserverSuspended = true;
1221
+ }
1222
+ _stopListeners() {
1223
+ if (this._scrollListener) {
1224
+ this._eventTarget.removeEventListener("scroll", this._scrollListener, false);
1225
+ delete this._scrollListener;
1226
+ }
1227
+ if (this._resizeListener) {
1228
+ if (this._isDocumentElement) {
1229
+ window.removeEventListener("resize", this._resizeListener, false);
1230
+ delete this._resizeListener;
1231
+ }
1232
+ }
1233
+ if (this._resizeObserver && this._el) {
1234
+ this._resizeObserver.unobserve(this._el);
1235
+ this._resizeObserver.disconnect();
1236
+ delete this._resizeObserver;
1237
+ }
1238
+ }
1239
+ _clearScrollingJudgeTimer() {
1240
+ if (this._scrollingJudgeTimerId !== null) {
1241
+ clearTimeout(this._scrollingJudgeTimerId);
1242
+ this._scrollingJudgeTimerId = null;
1243
+ }
1244
+ }
1245
+ _onResize(width, height) {
1246
+ this._update(width, height);
1247
+ }
1248
+ _triggerScrollTick(event) {
1249
+ const { _nowScrolling } = this;
1250
+ if (event === "scrollStart") {
1251
+ this._startX = this._scrollLeft;
1252
+ this._startY = this._scrollTop;
1253
+ this._lastTotalX = 0;
1254
+ this._lastTotalY = 0;
1255
+ this._nowScrolling = true;
1256
+ } else if (event === "scrollEnd") this._nowScrolling = false;
1257
+ if (_nowScrolling !== this._nowScrolling) this._syncToObservers("nowScrolling");
1258
+ this.emit(event, this.lastPayload);
1259
+ }
1260
+ _onScroll() {
1261
+ if (!this.scrollEnabled && this._el) {
1262
+ this._el.scrollLeft = this._scrollLeft;
1263
+ this._el.scrollTop = this._scrollTop;
1264
+ return;
1265
+ }
1266
+ const { _scrollTop, _scrollLeft, _lastAxis, _lastDirection, _lastXDirection, _lastYDirection } = this;
1267
+ this._updateScrollPositions();
1268
+ const tickedX = this._scrollLeft - _scrollLeft;
1269
+ const tickedY = this._scrollTop - _scrollTop;
1270
+ this._tickedX = tickedX;
1271
+ this._tickedY = tickedY;
1272
+ if (tickedX === tickedY) this._lastAxis = this.baseAxis;
1273
+ else this._lastAxis = Math.abs(tickedX) > Math.abs(tickedY) ? "x" : "y";
1274
+ if (_scrollTop < this._scrollTop) this._lastYDirection = "bottom";
1275
+ else if (_scrollTop > this._scrollTop) this._lastYDirection = "top";
1276
+ if (_scrollLeft < this._scrollLeft) this._lastXDirection = "right";
1277
+ else if (_scrollLeft > this._scrollLeft) this._lastXDirection = "left";
1278
+ this._lastDirection = this._lastAxis === "y" ? this._lastYDirection : this._lastXDirection;
1279
+ const axisIsChanged = this._lastAxis !== _lastAxis;
1280
+ const lastXDirectionIsChanged = this._lastXDirection !== _lastXDirection;
1281
+ const lastYDirectionIsChanged = this._lastYDirection !== _lastYDirection;
1282
+ const lastDirectionIsChanged = this._lastDirection !== _lastDirection;
1283
+ if (axisIsChanged) this.emit("changeAxis", this._lastAxis);
1284
+ if (lastXDirectionIsChanged) this.emit("changeLastXDirection", this._lastXDirection);
1285
+ if (lastYDirectionIsChanged) this.emit("changeLastYDirection", this._lastYDirection);
1286
+ if (lastDirectionIsChanged) this.emit("changeLastDirection", this._lastDirection);
1287
+ if (axisIsChanged || lastXDirectionIsChanged || lastYDirectionIsChanged || lastDirectionIsChanged) this._syncToObservers([
1288
+ "lastAxis",
1289
+ "lastDirection",
1290
+ "lastYDirection",
1291
+ "lastXDirection"
1292
+ ]);
1293
+ if (this._nowScrolling) if (axisIsChanged || _lastAxis === "y" && lastYDirectionIsChanged || _lastAxis === "x" && lastXDirectionIsChanged) this._triggerScrollTick("scrollEnd");
1294
+ else {
1295
+ this._lastTotalX = this._scrollLeft - this._startX;
1296
+ this._lastTotalY = this._scrollTop - this._startY;
1297
+ this._triggerScrollTick("scroll");
1298
+ }
1299
+ if (!this._nowScrolling) {
1300
+ this._updateScrollSize();
1301
+ this._triggerScrollTick("scrollStart");
1302
+ }
1303
+ this._clearScrollingJudgeTimer();
1304
+ this._scrollingJudgeTimerId = window.setTimeout(() => {
1305
+ this._triggerScrollTick("scrollEnd");
1306
+ }, this.scrollingJudgeInterval);
1307
+ }
1308
+ _syncToObserver(observer, keys = scrollerObservableKeys) {
1309
+ for (const key of keys) observer[key] = this[key];
1310
+ }
1311
+ _syncToObservers(keys) {
1312
+ if (this._observers.length === 0) return;
1313
+ keys = typeof keys === "string" ? [keys] : keys;
1314
+ for (const observer of this._observers) this._syncToObserver(observer, keys);
1315
+ }
1316
+ _checkElement() {
1317
+ const { _el } = this;
1318
+ if (!_el) {
1319
+ const message = "missing element";
1320
+ logger.error(message);
1321
+ throw new Error(message);
1322
+ }
1323
+ return _el;
1324
+ }
1325
+ _createMergedScrollOptions(source) {
1326
+ return {
1327
+ container: this._checkElement(),
1328
+ ...this.scrollSettingsDefaults,
1329
+ ...source
1330
+ };
1331
+ }
1332
+ _createMergedScrollToElementOptions(source) {
1333
+ const merged = {
1334
+ container: this._checkElement(),
1335
+ ...this.scrollToElementSettingsDefaults,
1336
+ ...source
1337
+ };
1338
+ let { _scrollToElementAdditionalOffset: additionalOffset } = this;
1339
+ if (!additionalOffset) return merged;
1340
+ if (typeof additionalOffset === "function") additionalOffset = additionalOffset(this);
1341
+ if (!additionalOffset) return merged;
1342
+ if (typeof additionalOffset === "number") additionalOffset = {
1343
+ x: additionalOffset,
1344
+ y: additionalOffset
1345
+ };
1346
+ let { offset } = merged;
1347
+ if (!offset) {
1348
+ merged.offset = additionalOffset;
1349
+ return merged;
1350
+ }
1351
+ if (typeof offset === "number") offset = {
1352
+ x: offset,
1353
+ y: offset
1354
+ };
1355
+ offset.x = (offset.x || 0) + (additionalOffset.x || 0);
1356
+ offset.y = (offset.y || 0) + (additionalOffset.y || 0);
1357
+ merged.offset = offset;
1358
+ return merged;
1359
+ }
1360
+ _clearScrollToResult() {
1361
+ if (!this._scrollToResult) return;
1362
+ this._scrollToResult = null;
1363
+ }
1364
+ _setScrollToResult(result) {
1365
+ this._scrollToResult = result;
1366
+ result.promise.then(() => {
1367
+ this._clearScrollToResult();
1368
+ });
1369
+ return result;
1370
+ }
1371
+ _updateScrollable() {
1372
+ if (this.scrollEnabled) this._scrollEnable();
1373
+ else this._scrollDisable();
1374
+ }
1375
+ _scrollEnable() {
1376
+ enableScroll(this._checkElement());
1377
+ }
1378
+ _scrollDisable() {
1379
+ const el = this._checkElement();
1380
+ this.cancel();
1381
+ disableScroll(el);
1382
+ }
1412
1383
  };
1413
-
1384
+ //#endregion
1414
1385
  export { SCROLLABLE_KEY_CODES, Scroller, ScrollerState, defaultBaseSettings, defaultSettings, disableScroll, enableScroll, scrollBy, scrollTo, scrollToBottom, scrollToElement, scrollToElementSettingsDefaults, scrollToLeft, scrollToLeftBottom, scrollToLeftTop, scrollToRight, scrollToRightBottom, scrollToRightTop, scrollToSide, scrollToTop };
1415
- //# sourceMappingURL=scroller.mjs.map
1386
+
1416
1387
  //# sourceMappingURL=scroller.mjs.map