소스 검색

Rename the Options component to "Media" and handle media queries by the component.

NaotoshiFujita 3 년 전
부모
커밋
d74f636504

+ 127 - 123
dist/js/splide.cjs.js

@@ -8,6 +8,39 @@
 
 Object.defineProperty(exports, '__esModule', { value: true });
 
+const EVENT_MOUNTED = "mounted";
+const EVENT_READY = "ready";
+const EVENT_MOVE = "move";
+const EVENT_MOVED = "moved";
+const EVENT_SHIFTED = "shifted";
+const EVENT_CLICK = "click";
+const EVENT_ACTIVE = "active";
+const EVENT_INACTIVE = "inactive";
+const EVENT_VISIBLE = "visible";
+const EVENT_HIDDEN = "hidden";
+const EVENT_SLIDE_KEYDOWN = "slide:keydown";
+const EVENT_REFRESH = "refresh";
+const EVENT_UPDATED = "updated";
+const EVENT_MEDIA = "media";
+const EVENT_RESIZE = "resize";
+const EVENT_RESIZED = "resized";
+const EVENT_REPOSITIONED = "repositioned";
+const EVENT_DRAG = "drag";
+const EVENT_DRAGGING = "dragging";
+const EVENT_DRAGGED = "dragged";
+const EVENT_SCROLL = "scroll";
+const EVENT_SCROLLED = "scrolled";
+const EVENT_DESTROY = "destroy";
+const EVENT_ARROWS_MOUNTED = "arrows:mounted";
+const EVENT_ARROWS_UPDATED = "arrows:updated";
+const EVENT_PAGINATION_MOUNTED = "pagination:mounted";
+const EVENT_PAGINATION_UPDATED = "pagination:updated";
+const EVENT_NAVIGATION_MOUNTED = "navigation:mounted";
+const EVENT_AUTOPLAY_PLAY = "autoplay:play";
+const EVENT_AUTOPLAY_PLAYING = "autoplay:playing";
+const EVENT_AUTOPLAY_PAUSE = "autoplay:pause";
+const EVENT_LAZYLOAD_LOADED = "lazyload:loaded";
+
 const CREATED = 1;
 const MOUNTED = 2;
 const IDLE = 3;
@@ -143,15 +176,17 @@ function assign(object) {
   return object;
 }
 
-function merge(object, source) {
-  forOwn(source, (value, key) => {
-    if (isArray(value)) {
-      object[key] = value.slice();
-    } else if (isObject(value)) {
-      object[key] = merge(isObject(object[key]) ? object[key] : {}, value);
-    } else {
-      object[key] = value;
-    }
+function merge(object) {
+  slice(arguments).forEach((source) => {
+    forOwn(source, (value, key) => {
+      if (isArray(value)) {
+        object[key] = value.slice();
+      } else if (isObject(value)) {
+        object[key] = merge(isObject(object[key]) ? object[key] : {}, value);
+      } else {
+        object[key] = value;
+      }
+    });
   });
   return object;
 }
@@ -333,7 +368,6 @@ function EventBus() {
     forEachEvent(events, (event, namespace) => {
       handlers[event] = handlers[event] || [];
       push(handlers[event], {
-        _event: event,
         _callback: callback,
         _namespace: namespace,
         _priority: priority,
@@ -343,8 +377,7 @@ function EventBus() {
   }
   function off(events, key) {
     forEachEvent(events, (event, namespace) => {
-      const eventHandlers = handlers[event];
-      handlers[event] = eventHandlers && eventHandlers.filter((handler) => {
+      handlers[event] = (handlers[event] || []).filter((handler) => {
         return handler._key ? handler._key !== key : key || handler._namespace !== namespace;
       });
     });
@@ -377,39 +410,7 @@ function EventBus() {
   };
 }
 
-const EVENT_MOUNTED = "mounted";
-const EVENT_READY = "ready";
-const EVENT_MOVE = "move";
-const EVENT_MOVED = "moved";
-const EVENT_SHIFTED = "shifted";
-const EVENT_CLICK = "click";
-const EVENT_ACTIVE = "active";
-const EVENT_INACTIVE = "inactive";
-const EVENT_VISIBLE = "visible";
-const EVENT_HIDDEN = "hidden";
-const EVENT_SLIDE_KEYDOWN = "slide:keydown";
-const EVENT_REFRESH = "refresh";
-const EVENT_UPDATED = "updated";
-const EVENT_RESIZE = "resize";
-const EVENT_RESIZED = "resized";
-const EVENT_REPOSITIONED = "repositioned";
-const EVENT_DRAG = "drag";
-const EVENT_DRAGGING = "dragging";
-const EVENT_DRAGGED = "dragged";
-const EVENT_SCROLL = "scroll";
-const EVENT_SCROLLED = "scrolled";
-const EVENT_DESTROY = "destroy";
-const EVENT_ARROWS_MOUNTED = "arrows:mounted";
-const EVENT_ARROWS_UPDATED = "arrows:updated";
-const EVENT_PAGINATION_MOUNTED = "pagination:mounted";
-const EVENT_PAGINATION_UPDATED = "pagination:updated";
-const EVENT_NAVIGATION_MOUNTED = "navigation:mounted";
-const EVENT_AUTOPLAY_PLAY = "autoplay:play";
-const EVENT_AUTOPLAY_PLAYING = "autoplay:playing";
-const EVENT_AUTOPLAY_PAUSE = "autoplay:pause";
-const EVENT_LAZYLOAD_LOADED = "lazyload:loaded";
-
-function EventInterface(Splide2) {
+function EventInterface(Splide2, manual) {
   const { event } = Splide2;
   const key = {};
   let listeners = [];
@@ -421,15 +422,17 @@ function EventInterface(Splide2) {
   }
   function bind(targets, events, callback, options) {
     forEachEvent(targets, events, (target, event2) => {
-      listeners.push([target, event2, callback, options]);
-      target.addEventListener(event2, callback, options);
+      const isEventTarget = "addEventListener" in target;
+      const remover = isEventTarget ? target.removeEventListener.bind(target, event2, callback, options) : target["removeListener"].bind(target, callback);
+      isEventTarget ? target.addEventListener(event2, callback, options) : target["addListener"](callback);
+      listeners.push([target, event2, callback, remover]);
     });
   }
   function unbind(targets, events, callback) {
     forEachEvent(targets, events, (target, event2) => {
       listeners = listeners.filter((listener) => {
         if (listener[0] === target && listener[1] === event2 && (!callback || listener[2] === callback)) {
-          target.removeEventListener(event2, listener[2], listener[3]);
+          listener[3]();
           return false;
         }
         return true;
@@ -444,10 +447,12 @@ function EventInterface(Splide2) {
     });
   }
   function destroy() {
-    listeners = listeners.filter((data) => unbind(data[0], data[1]));
+    listeners = listeners.filter((data) => {
+      data[3]();
+    });
     event.offBy(key);
   }
-  event.on(EVENT_DESTROY, destroy, key);
+  !manual && event.on(EVENT_DESTROY, destroy, key);
   return {
     on,
     off,
@@ -539,8 +544,9 @@ function Throttle(func, duration) {
   let interval;
   function throttled() {
     if (!interval) {
+      const args = slice(arguments);
       interval = RequestInterval(duration || 0, () => {
-        func.apply(this, arguments);
+        func.apply(this, args);
         interval = null;
       }, null, 1);
       interval.start();
@@ -549,55 +555,55 @@ function Throttle(func, duration) {
   return throttled;
 }
 
-function Options(Splide2, Components2, options) {
-  const throttledObserve = Throttle(observe);
-  let initialOptions;
-  let points;
-  let currPoint;
+function Media(Splide2, Components2, options) {
+  const event = EventInterface(Splide2, true);
+  const breakpoints = options.breakpoints || {};
+  const userOptions = merge({}, options);
+  const queries = [];
   function setup() {
-    initialOptions = merge({}, options);
-    const { breakpoints } = options;
-    if (breakpoints) {
-      const isMin = options.mediaQuery === "min";
-      points = Object.keys(breakpoints).sort((n, m) => isMin ? +m - +n : +n - +m).map((point) => [
-        point,
-        matchMedia(`(${isMin ? "min" : "max"}-width:${point}px)`)
-      ]);
-      observe();
-    }
-  }
-  function mount() {
-    if (points) {
-      addEventListener("resize", throttledObserve);
-    }
+    const isMin = options.mediaQuery === "min";
+    register(Object.keys(breakpoints).sort((n, m) => isMin ? +m - +n : +n - +m).map((key) => [breakpoints[key], `(${isMin ? "min" : "max"}-width:${key}px)`]).concat([[userOptions]]));
+    register([[{
+      speed: 0,
+      autoplay: "pause"
+    }, "(prefers-reduced-motion: reduce)"]]);
+    update();
   }
   function destroy(completely) {
     if (completely) {
-      removeEventListener("resize", throttledObserve);
+      event.destroy();
     }
   }
-  function observe() {
-    const item = find(points, (item2) => item2[1].matches) || [];
-    if (item[0] !== currPoint) {
-      onMatch(currPoint = item[0]);
-    }
+  function register(entries) {
+    queries.push(entries.map((entry) => {
+      const query = entry[1] && matchMedia(entry[1]);
+      query && event.bind(query, "change", update);
+      return [entry[0], query];
+    }));
   }
-  function onMatch(point) {
-    const newOptions = options.breakpoints[point] || initialOptions;
-    if (newOptions.destroy) {
-      Splide2.options = initialOptions;
-      Splide2.destroy(newOptions.destroy === "completely");
+  function update() {
+    const options2 = accumulate();
+    const { destroy: _destroy } = options2;
+    if (_destroy) {
+      Splide2.options = userOptions;
+      Splide2.destroy(_destroy === "completely");
+    } else if (Splide2.state.is(DESTROYED)) {
+      destroy(true);
+      Splide2.mount();
     } else {
-      if (Splide2.state.is(DESTROYED)) {
-        destroy(true);
-        Splide2.mount();
-      }
-      Splide2.options = newOptions;
+      Splide2.options = options2;
     }
   }
+  function accumulate() {
+    return queries.reduce((merged, entries) => {
+      const entry = find(entries, (entry2) => !entry2[1] || entry2[1].matches) || [];
+      entry[1] && event.emit(EVENT_MEDIA, entry[1]);
+      return merge(merged, entry[0] || {});
+    }, merge({}, userOptions));
+  }
   return {
     setup,
-    mount,
+    mount: noop,
     destroy
   };
 }
@@ -1025,7 +1031,7 @@ function Layout(Splide2, Components2, options) {
   let rootRect;
   function mount() {
     init();
-    bind(window, "resize load", Throttle(emit.bind(this, EVENT_RESIZE)));
+    bind(window, "resize load", Throttle(apply(emit, EVENT_RESIZE)));
     on([EVENT_UPDATED, EVENT_REFRESH], init);
     on(EVENT_RESIZE, resize);
   }
@@ -1555,18 +1561,16 @@ function Autoplay(Splide2, Components2, options) {
   const interval = RequestInterval(options.interval, Splide2.go.bind(Splide2, ">"), update);
   const { isPaused } = interval;
   const { Elements } = Components2;
+  const { autoplay } = options;
   let hovered;
   let focused;
-  let paused;
+  let paused = autoplay === "pause";
   function mount() {
-    const { autoplay } = options;
     if (autoplay) {
       initButton(true);
       initButton(false);
       listen();
-      if (autoplay !== "pause") {
-        play();
-      }
+      !paused && play();
     }
   }
   function initButton(forPause) {
@@ -2197,29 +2201,6 @@ function Sync(Splide2, Components2, options) {
   };
 }
 
-function Live(Splide2, Components2, options) {
-  const { on } = EventInterface(Splide2);
-  const { list } = Components2.Elements;
-  const { live } = options;
-  function mount() {
-    if (live) {
-      setAttribute(list, ARIA_ATOMIC, false);
-      disable(!Components2.Autoplay.isPaused());
-      on(EVENT_AUTOPLAY_PLAY, apply(disable, true));
-      on(EVENT_AUTOPLAY_PAUSE, apply(disable, false));
-    }
-  }
-  function disable(disabled) {
-    if (live) {
-      setAttribute(list, ARIA_LIVE, disabled ? "off" : "polite");
-    }
-  }
-  return {
-    mount,
-    disable
-  };
-}
-
 function Wheel(Splide2, Components2, options) {
   const { bind } = EventInterface(Splide2);
   function mount() {
@@ -2245,9 +2226,32 @@ function Wheel(Splide2, Components2, options) {
   };
 }
 
+function Live(Splide2, Components2, options) {
+  const { on } = EventInterface(Splide2);
+  const { list } = Components2.Elements;
+  const { live } = options;
+  function mount() {
+    if (live) {
+      setAttribute(list, ARIA_ATOMIC, false);
+      disable(!Components2.Autoplay.isPaused());
+      on(EVENT_AUTOPLAY_PLAY, apply(disable, true));
+      on(EVENT_AUTOPLAY_PAUSE, apply(disable, false));
+    }
+  }
+  function disable(disabled) {
+    if (live) {
+      setAttribute(list, ARIA_LIVE, disabled ? "off" : "polite");
+    }
+  }
+  return {
+    mount,
+    disable
+  };
+}
+
 var ComponentConstructors = /*#__PURE__*/Object.freeze({
   __proto__: null,
-  Options: Options,
+  Media: Media,
   Direction: Direction,
   Elements: Elements,
   Slides: Slides,
@@ -2264,8 +2268,8 @@ var ComponentConstructors = /*#__PURE__*/Object.freeze({
   LazyLoad: LazyLoad,
   Pagination: Pagination,
   Sync: Sync,
-  Live: Live,
-  Wheel: Wheel
+  Wheel: Wheel,
+  Live: Live
 });
 
 const I18N = {
@@ -2391,12 +2395,11 @@ const _Splide = class {
     const root = isString(target) ? query(document, target) : target;
     assert(root, `${root} is invalid.`);
     this.root = root;
-    merge(DEFAULTS, _Splide.defaults);
-    merge(merge(this._options, DEFAULTS), options || {});
+    merge(this._options, DEFAULTS, _Splide.defaults, options || {});
     try {
       merge(this._options, JSON.parse(getAttribute(root, DATA_ATTRIBUTE)));
     } catch (e) {
-      assert(false, e.message);
+      assert(false, "Invalid JSON");
     }
   }
   mount(Extensions, Transition) {
@@ -2905,6 +2908,7 @@ exports.EVENT_DRAGGING = EVENT_DRAGGING;
 exports.EVENT_HIDDEN = EVENT_HIDDEN;
 exports.EVENT_INACTIVE = EVENT_INACTIVE;
 exports.EVENT_LAZYLOAD_LOADED = EVENT_LAZYLOAD_LOADED;
+exports.EVENT_MEDIA = EVENT_MEDIA;
 exports.EVENT_MOUNTED = EVENT_MOUNTED;
 exports.EVENT_MOVE = EVENT_MOVE;
 exports.EVENT_MOVED = EVENT_MOVED;

+ 127 - 124
dist/js/splide.esm.js

@@ -4,6 +4,39 @@
  * License  : MIT
  * Copyright: 2022 Naotoshi Fujita
  */
+const EVENT_MOUNTED = "mounted";
+const EVENT_READY = "ready";
+const EVENT_MOVE = "move";
+const EVENT_MOVED = "moved";
+const EVENT_SHIFTED = "shifted";
+const EVENT_CLICK = "click";
+const EVENT_ACTIVE = "active";
+const EVENT_INACTIVE = "inactive";
+const EVENT_VISIBLE = "visible";
+const EVENT_HIDDEN = "hidden";
+const EVENT_SLIDE_KEYDOWN = "slide:keydown";
+const EVENT_REFRESH = "refresh";
+const EVENT_UPDATED = "updated";
+const EVENT_MEDIA = "media";
+const EVENT_RESIZE = "resize";
+const EVENT_RESIZED = "resized";
+const EVENT_REPOSITIONED = "repositioned";
+const EVENT_DRAG = "drag";
+const EVENT_DRAGGING = "dragging";
+const EVENT_DRAGGED = "dragged";
+const EVENT_SCROLL = "scroll";
+const EVENT_SCROLLED = "scrolled";
+const EVENT_DESTROY = "destroy";
+const EVENT_ARROWS_MOUNTED = "arrows:mounted";
+const EVENT_ARROWS_UPDATED = "arrows:updated";
+const EVENT_PAGINATION_MOUNTED = "pagination:mounted";
+const EVENT_PAGINATION_UPDATED = "pagination:updated";
+const EVENT_NAVIGATION_MOUNTED = "navigation:mounted";
+const EVENT_AUTOPLAY_PLAY = "autoplay:play";
+const EVENT_AUTOPLAY_PLAYING = "autoplay:playing";
+const EVENT_AUTOPLAY_PAUSE = "autoplay:pause";
+const EVENT_LAZYLOAD_LOADED = "lazyload:loaded";
+
 const CREATED = 1;
 const MOUNTED = 2;
 const IDLE = 3;
@@ -139,15 +172,17 @@ function assign(object) {
   return object;
 }
 
-function merge(object, source) {
-  forOwn(source, (value, key) => {
-    if (isArray(value)) {
-      object[key] = value.slice();
-    } else if (isObject(value)) {
-      object[key] = merge(isObject(object[key]) ? object[key] : {}, value);
-    } else {
-      object[key] = value;
-    }
+function merge(object) {
+  slice(arguments).forEach((source) => {
+    forOwn(source, (value, key) => {
+      if (isArray(value)) {
+        object[key] = value.slice();
+      } else if (isObject(value)) {
+        object[key] = merge(isObject(object[key]) ? object[key] : {}, value);
+      } else {
+        object[key] = value;
+      }
+    });
   });
   return object;
 }
@@ -329,7 +364,6 @@ function EventBus() {
     forEachEvent(events, (event, namespace) => {
       handlers[event] = handlers[event] || [];
       push(handlers[event], {
-        _event: event,
         _callback: callback,
         _namespace: namespace,
         _priority: priority,
@@ -339,8 +373,7 @@ function EventBus() {
   }
   function off(events, key) {
     forEachEvent(events, (event, namespace) => {
-      const eventHandlers = handlers[event];
-      handlers[event] = eventHandlers && eventHandlers.filter((handler) => {
+      handlers[event] = (handlers[event] || []).filter((handler) => {
         return handler._key ? handler._key !== key : key || handler._namespace !== namespace;
       });
     });
@@ -373,39 +406,7 @@ function EventBus() {
   };
 }
 
-const EVENT_MOUNTED = "mounted";
-const EVENT_READY = "ready";
-const EVENT_MOVE = "move";
-const EVENT_MOVED = "moved";
-const EVENT_SHIFTED = "shifted";
-const EVENT_CLICK = "click";
-const EVENT_ACTIVE = "active";
-const EVENT_INACTIVE = "inactive";
-const EVENT_VISIBLE = "visible";
-const EVENT_HIDDEN = "hidden";
-const EVENT_SLIDE_KEYDOWN = "slide:keydown";
-const EVENT_REFRESH = "refresh";
-const EVENT_UPDATED = "updated";
-const EVENT_RESIZE = "resize";
-const EVENT_RESIZED = "resized";
-const EVENT_REPOSITIONED = "repositioned";
-const EVENT_DRAG = "drag";
-const EVENT_DRAGGING = "dragging";
-const EVENT_DRAGGED = "dragged";
-const EVENT_SCROLL = "scroll";
-const EVENT_SCROLLED = "scrolled";
-const EVENT_DESTROY = "destroy";
-const EVENT_ARROWS_MOUNTED = "arrows:mounted";
-const EVENT_ARROWS_UPDATED = "arrows:updated";
-const EVENT_PAGINATION_MOUNTED = "pagination:mounted";
-const EVENT_PAGINATION_UPDATED = "pagination:updated";
-const EVENT_NAVIGATION_MOUNTED = "navigation:mounted";
-const EVENT_AUTOPLAY_PLAY = "autoplay:play";
-const EVENT_AUTOPLAY_PLAYING = "autoplay:playing";
-const EVENT_AUTOPLAY_PAUSE = "autoplay:pause";
-const EVENT_LAZYLOAD_LOADED = "lazyload:loaded";
-
-function EventInterface(Splide2) {
+function EventInterface(Splide2, manual) {
   const { event } = Splide2;
   const key = {};
   let listeners = [];
@@ -417,15 +418,17 @@ function EventInterface(Splide2) {
   }
   function bind(targets, events, callback, options) {
     forEachEvent(targets, events, (target, event2) => {
-      listeners.push([target, event2, callback, options]);
-      target.addEventListener(event2, callback, options);
+      const isEventTarget = "addEventListener" in target;
+      const remover = isEventTarget ? target.removeEventListener.bind(target, event2, callback, options) : target["removeListener"].bind(target, callback);
+      isEventTarget ? target.addEventListener(event2, callback, options) : target["addListener"](callback);
+      listeners.push([target, event2, callback, remover]);
     });
   }
   function unbind(targets, events, callback) {
     forEachEvent(targets, events, (target, event2) => {
       listeners = listeners.filter((listener) => {
         if (listener[0] === target && listener[1] === event2 && (!callback || listener[2] === callback)) {
-          target.removeEventListener(event2, listener[2], listener[3]);
+          listener[3]();
           return false;
         }
         return true;
@@ -440,10 +443,12 @@ function EventInterface(Splide2) {
     });
   }
   function destroy() {
-    listeners = listeners.filter((data) => unbind(data[0], data[1]));
+    listeners = listeners.filter((data) => {
+      data[3]();
+    });
     event.offBy(key);
   }
-  event.on(EVENT_DESTROY, destroy, key);
+  !manual && event.on(EVENT_DESTROY, destroy, key);
   return {
     on,
     off,
@@ -535,8 +540,9 @@ function Throttle(func, duration) {
   let interval;
   function throttled() {
     if (!interval) {
+      const args = slice(arguments);
       interval = RequestInterval(duration || 0, () => {
-        func.apply(this, arguments);
+        func.apply(this, args);
         interval = null;
       }, null, 1);
       interval.start();
@@ -545,55 +551,55 @@ function Throttle(func, duration) {
   return throttled;
 }
 
-function Options(Splide2, Components2, options) {
-  const throttledObserve = Throttle(observe);
-  let initialOptions;
-  let points;
-  let currPoint;
+function Media(Splide2, Components2, options) {
+  const event = EventInterface(Splide2, true);
+  const breakpoints = options.breakpoints || {};
+  const userOptions = merge({}, options);
+  const queries = [];
   function setup() {
-    initialOptions = merge({}, options);
-    const { breakpoints } = options;
-    if (breakpoints) {
-      const isMin = options.mediaQuery === "min";
-      points = Object.keys(breakpoints).sort((n, m) => isMin ? +m - +n : +n - +m).map((point) => [
-        point,
-        matchMedia(`(${isMin ? "min" : "max"}-width:${point}px)`)
-      ]);
-      observe();
-    }
-  }
-  function mount() {
-    if (points) {
-      addEventListener("resize", throttledObserve);
-    }
+    const isMin = options.mediaQuery === "min";
+    register(Object.keys(breakpoints).sort((n, m) => isMin ? +m - +n : +n - +m).map((key) => [breakpoints[key], `(${isMin ? "min" : "max"}-width:${key}px)`]).concat([[userOptions]]));
+    register([[{
+      speed: 0,
+      autoplay: "pause"
+    }, "(prefers-reduced-motion: reduce)"]]);
+    update();
   }
   function destroy(completely) {
     if (completely) {
-      removeEventListener("resize", throttledObserve);
+      event.destroy();
     }
   }
-  function observe() {
-    const item = find(points, (item2) => item2[1].matches) || [];
-    if (item[0] !== currPoint) {
-      onMatch(currPoint = item[0]);
-    }
+  function register(entries) {
+    queries.push(entries.map((entry) => {
+      const query = entry[1] && matchMedia(entry[1]);
+      query && event.bind(query, "change", update);
+      return [entry[0], query];
+    }));
   }
-  function onMatch(point) {
-    const newOptions = options.breakpoints[point] || initialOptions;
-    if (newOptions.destroy) {
-      Splide2.options = initialOptions;
-      Splide2.destroy(newOptions.destroy === "completely");
+  function update() {
+    const options2 = accumulate();
+    const { destroy: _destroy } = options2;
+    if (_destroy) {
+      Splide2.options = userOptions;
+      Splide2.destroy(_destroy === "completely");
+    } else if (Splide2.state.is(DESTROYED)) {
+      destroy(true);
+      Splide2.mount();
     } else {
-      if (Splide2.state.is(DESTROYED)) {
-        destroy(true);
-        Splide2.mount();
-      }
-      Splide2.options = newOptions;
+      Splide2.options = options2;
     }
   }
+  function accumulate() {
+    return queries.reduce((merged, entries) => {
+      const entry = find(entries, (entry2) => !entry2[1] || entry2[1].matches) || [];
+      entry[1] && event.emit(EVENT_MEDIA, entry[1]);
+      return merge(merged, entry[0] || {});
+    }, merge({}, userOptions));
+  }
   return {
     setup,
-    mount,
+    mount: noop,
     destroy
   };
 }
@@ -1021,7 +1027,7 @@ function Layout(Splide2, Components2, options) {
   let rootRect;
   function mount() {
     init();
-    bind(window, "resize load", Throttle(emit.bind(this, EVENT_RESIZE)));
+    bind(window, "resize load", Throttle(apply(emit, EVENT_RESIZE)));
     on([EVENT_UPDATED, EVENT_REFRESH], init);
     on(EVENT_RESIZE, resize);
   }
@@ -1551,18 +1557,16 @@ function Autoplay(Splide2, Components2, options) {
   const interval = RequestInterval(options.interval, Splide2.go.bind(Splide2, ">"), update);
   const { isPaused } = interval;
   const { Elements } = Components2;
+  const { autoplay } = options;
   let hovered;
   let focused;
-  let paused;
+  let paused = autoplay === "pause";
   function mount() {
-    const { autoplay } = options;
     if (autoplay) {
       initButton(true);
       initButton(false);
       listen();
-      if (autoplay !== "pause") {
-        play();
-      }
+      !paused && play();
     }
   }
   function initButton(forPause) {
@@ -2193,29 +2197,6 @@ function Sync(Splide2, Components2, options) {
   };
 }
 
-function Live(Splide2, Components2, options) {
-  const { on } = EventInterface(Splide2);
-  const { list } = Components2.Elements;
-  const { live } = options;
-  function mount() {
-    if (live) {
-      setAttribute(list, ARIA_ATOMIC, false);
-      disable(!Components2.Autoplay.isPaused());
-      on(EVENT_AUTOPLAY_PLAY, apply(disable, true));
-      on(EVENT_AUTOPLAY_PAUSE, apply(disable, false));
-    }
-  }
-  function disable(disabled) {
-    if (live) {
-      setAttribute(list, ARIA_LIVE, disabled ? "off" : "polite");
-    }
-  }
-  return {
-    mount,
-    disable
-  };
-}
-
 function Wheel(Splide2, Components2, options) {
   const { bind } = EventInterface(Splide2);
   function mount() {
@@ -2241,9 +2222,32 @@ function Wheel(Splide2, Components2, options) {
   };
 }
 
+function Live(Splide2, Components2, options) {
+  const { on } = EventInterface(Splide2);
+  const { list } = Components2.Elements;
+  const { live } = options;
+  function mount() {
+    if (live) {
+      setAttribute(list, ARIA_ATOMIC, false);
+      disable(!Components2.Autoplay.isPaused());
+      on(EVENT_AUTOPLAY_PLAY, apply(disable, true));
+      on(EVENT_AUTOPLAY_PAUSE, apply(disable, false));
+    }
+  }
+  function disable(disabled) {
+    if (live) {
+      setAttribute(list, ARIA_LIVE, disabled ? "off" : "polite");
+    }
+  }
+  return {
+    mount,
+    disable
+  };
+}
+
 var ComponentConstructors = /*#__PURE__*/Object.freeze({
   __proto__: null,
-  Options: Options,
+  Media: Media,
   Direction: Direction,
   Elements: Elements,
   Slides: Slides,
@@ -2260,8 +2264,8 @@ var ComponentConstructors = /*#__PURE__*/Object.freeze({
   LazyLoad: LazyLoad,
   Pagination: Pagination,
   Sync: Sync,
-  Live: Live,
-  Wheel: Wheel
+  Wheel: Wheel,
+  Live: Live
 });
 
 const I18N = {
@@ -2387,12 +2391,11 @@ const _Splide = class {
     const root = isString(target) ? query(document, target) : target;
     assert(root, `${root} is invalid.`);
     this.root = root;
-    merge(DEFAULTS, _Splide.defaults);
-    merge(merge(this._options, DEFAULTS), options || {});
+    merge(this._options, DEFAULTS, _Splide.defaults, options || {});
     try {
       merge(this._options, JSON.parse(getAttribute(root, DATA_ATTRIBUTE)));
     } catch (e) {
-      assert(false, e.message);
+      assert(false, "Invalid JSON");
     }
   }
   mount(Extensions, Transition) {
@@ -2860,4 +2863,4 @@ class SplideRenderer {
   }
 }
 
-export { CLASSES, CLASS_ACTIVE, CLASS_ARROW, CLASS_ARROWS, CLASS_ARROW_NEXT, CLASS_ARROW_PREV, CLASS_AUTOPLAY, CLASS_CLONE, CLASS_CONTAINER, CLASS_INITIALIZED, CLASS_LIST, CLASS_LOADING, CLASS_NEXT, CLASS_PAGINATION, CLASS_PAGINATION_PAGE, CLASS_PAUSE, CLASS_PLAY, CLASS_PREV, CLASS_PROGRESS, CLASS_PROGRESS_BAR, CLASS_ROOT, CLASS_SLIDE, CLASS_SLIDER, CLASS_SPINNER, CLASS_SR, CLASS_TRACK, CLASS_VISIBLE, EVENT_ACTIVE, EVENT_ARROWS_MOUNTED, EVENT_ARROWS_UPDATED, EVENT_AUTOPLAY_PAUSE, EVENT_AUTOPLAY_PLAY, EVENT_AUTOPLAY_PLAYING, EVENT_CLICK, EVENT_DESTROY, EVENT_DRAG, EVENT_DRAGGED, EVENT_DRAGGING, EVENT_HIDDEN, EVENT_INACTIVE, EVENT_LAZYLOAD_LOADED, EVENT_MOUNTED, EVENT_MOVE, EVENT_MOVED, EVENT_NAVIGATION_MOUNTED, EVENT_PAGINATION_MOUNTED, EVENT_PAGINATION_UPDATED, EVENT_READY, EVENT_REFRESH, EVENT_REPOSITIONED, EVENT_RESIZE, EVENT_RESIZED, EVENT_SCROLL, EVENT_SCROLLED, EVENT_SHIFTED, EVENT_SLIDE_KEYDOWN, EVENT_UPDATED, EVENT_VISIBLE, EventBus, EventInterface, RequestInterval, STATUS_CLASSES, Splide, SplideRenderer, State, Throttle, Splide as default };
+export { CLASSES, CLASS_ACTIVE, CLASS_ARROW, CLASS_ARROWS, CLASS_ARROW_NEXT, CLASS_ARROW_PREV, CLASS_AUTOPLAY, CLASS_CLONE, CLASS_CONTAINER, CLASS_INITIALIZED, CLASS_LIST, CLASS_LOADING, CLASS_NEXT, CLASS_PAGINATION, CLASS_PAGINATION_PAGE, CLASS_PAUSE, CLASS_PLAY, CLASS_PREV, CLASS_PROGRESS, CLASS_PROGRESS_BAR, CLASS_ROOT, CLASS_SLIDE, CLASS_SLIDER, CLASS_SPINNER, CLASS_SR, CLASS_TRACK, CLASS_VISIBLE, EVENT_ACTIVE, EVENT_ARROWS_MOUNTED, EVENT_ARROWS_UPDATED, EVENT_AUTOPLAY_PAUSE, EVENT_AUTOPLAY_PLAY, EVENT_AUTOPLAY_PLAYING, EVENT_CLICK, EVENT_DESTROY, EVENT_DRAG, EVENT_DRAGGED, EVENT_DRAGGING, EVENT_HIDDEN, EVENT_INACTIVE, EVENT_LAZYLOAD_LOADED, EVENT_MEDIA, EVENT_MOUNTED, EVENT_MOVE, EVENT_MOVED, EVENT_NAVIGATION_MOUNTED, EVENT_PAGINATION_MOUNTED, EVENT_PAGINATION_UPDATED, EVENT_READY, EVENT_REFRESH, EVENT_REPOSITIONED, EVENT_RESIZE, EVENT_RESIZED, EVENT_SCROLL, EVENT_SCROLLED, EVENT_SHIFTED, EVENT_SLIDE_KEYDOWN, EVENT_UPDATED, EVENT_VISIBLE, EventBus, EventInterface, RequestInterval, STATUS_CLASSES, Splide, SplideRenderer, State, Throttle, Splide as default };

+ 79 - 111
dist/js/splide.js

@@ -13,6 +13,38 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
 })(this, function () {
   'use strict';
 
+  var EVENT_MOUNTED = "mounted";
+  var EVENT_READY = "ready";
+  var EVENT_MOVE = "move";
+  var EVENT_MOVED = "moved";
+  var EVENT_SHIFTED = "shifted";
+  var EVENT_CLICK = "click";
+  var EVENT_ACTIVE = "active";
+  var EVENT_INACTIVE = "inactive";
+  var EVENT_VISIBLE = "visible";
+  var EVENT_HIDDEN = "hidden";
+  var EVENT_SLIDE_KEYDOWN = "slide:keydown";
+  var EVENT_REFRESH = "refresh";
+  var EVENT_UPDATED = "updated";
+  var EVENT_MEDIA = "media";
+  var EVENT_RESIZE = "resize";
+  var EVENT_RESIZED = "resized";
+  var EVENT_REPOSITIONED = "repositioned";
+  var EVENT_DRAG = "drag";
+  var EVENT_DRAGGING = "dragging";
+  var EVENT_DRAGGED = "dragged";
+  var EVENT_SCROLL = "scroll";
+  var EVENT_SCROLLED = "scrolled";
+  var EVENT_DESTROY = "destroy";
+  var EVENT_ARROWS_MOUNTED = "arrows:mounted";
+  var EVENT_ARROWS_UPDATED = "arrows:updated";
+  var EVENT_PAGINATION_MOUNTED = "pagination:mounted";
+  var EVENT_PAGINATION_UPDATED = "pagination:updated";
+  var EVENT_NAVIGATION_MOUNTED = "navigation:mounted";
+  var EVENT_AUTOPLAY_PLAY = "autoplay:play";
+  var EVENT_AUTOPLAY_PLAYING = "autoplay:playing";
+  var EVENT_AUTOPLAY_PAUSE = "autoplay:pause";
+  var EVENT_LAZYLOAD_LOADED = "lazyload:loaded";
   var CREATED = 1;
   var MOUNTED = 2;
   var IDLE = 3;
@@ -366,7 +398,6 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
       forEachEvent(events, function (event, namespace) {
         handlers[event] = handlers[event] || [];
         push(handlers[event], {
-          _event: event,
           _callback: callback,
           _namespace: namespace,
           _priority: priority,
@@ -379,8 +410,7 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
 
     function off(events, key) {
       forEachEvent(events, function (event, namespace) {
-        var eventHandlers = handlers[event];
-        handlers[event] = eventHandlers && eventHandlers.filter(function (handler) {
+        handlers[event] = (handlers[event] || []).filter(function (handler) {
           return handler._key ? handler._key !== key : key || handler._namespace !== namespace;
         });
       });
@@ -419,38 +449,6 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
     };
   }
 
-  var EVENT_MOUNTED = "mounted";
-  var EVENT_READY = "ready";
-  var EVENT_MOVE = "move";
-  var EVENT_MOVED = "moved";
-  var EVENT_SHIFTED = "shifted";
-  var EVENT_CLICK = "click";
-  var EVENT_ACTIVE = "active";
-  var EVENT_INACTIVE = "inactive";
-  var EVENT_VISIBLE = "visible";
-  var EVENT_HIDDEN = "hidden";
-  var EVENT_SLIDE_KEYDOWN = "slide:keydown";
-  var EVENT_REFRESH = "refresh";
-  var EVENT_UPDATED = "updated";
-  var EVENT_RESIZE = "resize";
-  var EVENT_RESIZED = "resized";
-  var EVENT_REPOSITIONED = "repositioned";
-  var EVENT_DRAG = "drag";
-  var EVENT_DRAGGING = "dragging";
-  var EVENT_DRAGGED = "dragged";
-  var EVENT_SCROLL = "scroll";
-  var EVENT_SCROLLED = "scrolled";
-  var EVENT_DESTROY = "destroy";
-  var EVENT_ARROWS_MOUNTED = "arrows:mounted";
-  var EVENT_ARROWS_UPDATED = "arrows:updated";
-  var EVENT_PAGINATION_MOUNTED = "pagination:mounted";
-  var EVENT_PAGINATION_UPDATED = "pagination:updated";
-  var EVENT_NAVIGATION_MOUNTED = "navigation:mounted";
-  var EVENT_AUTOPLAY_PLAY = "autoplay:play";
-  var EVENT_AUTOPLAY_PLAYING = "autoplay:playing";
-  var EVENT_AUTOPLAY_PAUSE = "autoplay:pause";
-  var EVENT_LAZYLOAD_LOADED = "lazyload:loaded";
-
   function EventInterface(Splide2, manual) {
     var event = Splide2.event;
     var key = {};
@@ -628,23 +626,24 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
     return throttled;
   }
 
-  function Options(Splide2, Components2, options) {
+  function Media(Splide2, Components2, options) {
     var event = EventInterface(Splide2, true);
     var breakpoints = options.breakpoints || {};
     var userOptions = merge({}, options);
-    var fixedOptions = {};
-    var points;
+    var queries = [];
 
     function setup() {
       var isMin = options.mediaQuery === "min";
-      points = Object.keys(breakpoints).sort(function (n, m) {
+      register(Object.keys(breakpoints).sort(function (n, m) {
         return isMin ? +m - +n : +n - +m;
-      }).map(function (point) {
-        var queryList = matchMedia("(" + (isMin ? "min" : "max") + "-width:" + point + "px)");
-        event.bind(queryList, "change", check);
-        return [point, queryList];
-      });
-      check();
+      }).map(function (key) {
+        return [breakpoints[key], "(" + (isMin ? "min" : "max") + "-width:" + key + "px)"];
+      }).concat([[userOptions]]));
+      register([[{
+        speed: 0,
+        autoplay: "pause"
+      }, "(prefers-reduced-motion: reduce)"]]);
+      update();
     }
 
     function destroy(completely) {
@@ -653,42 +652,43 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
       }
     }
 
-    function check() {
-      var point = (find(points, function (item) {
-        return item[1].matches;
-      }) || [])[0];
-      var newOptions = merge({}, breakpoints[point] || userOptions, fixedOptions);
+    function register(entries) {
+      queries.push(entries.map(function (entry) {
+        var query = entry[1] && matchMedia(entry[1]);
+        query && event.bind(query, "change", update);
+        return [entry[0], query];
+      }));
+    }
+
+    function update() {
+      var options2 = accumulate();
+      var _destroy = options2.destroy;
 
-      if (newOptions.destroy) {
+      if (_destroy) {
         Splide2.options = userOptions;
-        Splide2.destroy(newOptions.destroy === "completely");
+        Splide2.destroy(_destroy === "completely");
+      } else if (Splide2.state.is(DESTROYED)) {
+        destroy(true);
+        Splide2.mount();
       } else {
-        if (Splide2.state.is(DESTROYED)) {
-          destroy(true);
-          Splide2.mount();
-        } else {
-          Splide2.options = newOptions;
-        }
+        Splide2.options = options2;
       }
     }
 
-    function fix(key, value) {
-      if (fixedOptions[key] !== value) {
-        if (isUndefined(value)) {
-          delete fixedOptions[key];
-        } else {
-          fixedOptions[key] = value;
-        }
-
-        check();
-      }
+    function accumulate() {
+      return queries.reduce(function (merged, entries) {
+        var entry = find(entries, function (entry2) {
+          return !entry2[1] || entry2[1].matches;
+        }) || [];
+        entry[1] && event.emit(EVENT_MEDIA, entry[1]);
+        return merge(merged, entry[0] || {});
+      }, merge({}, userOptions));
     }
 
     return {
       setup: setup,
       mount: noop,
-      destroy: destroy,
-      fix: fix
+      destroy: destroy
     };
   }
 
@@ -1847,21 +1847,17 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
     var interval = RequestInterval(options.interval, Splide2.go.bind(Splide2, ">"), update);
     var isPaused = interval.isPaused;
     var Elements = Components2.Elements;
+    var autoplay = options.autoplay;
     var hovered;
     var focused;
-    var paused;
+    var paused = autoplay === "pause";
 
     function mount() {
-      var autoplay = options.autoplay;
-
       if (autoplay) {
         initButton(true);
         initButton(false);
         listen();
-
-        if (autoplay !== "pause") {
-          play();
-        }
+        !paused && play();
       }
     }
 
@@ -2729,36 +2725,9 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
     };
   }
 
-  function Motion(Splide2, Components2, options) {
-    var _EventInterface18 = EventInterface(Splide2),
-        bind = _EventInterface18.bind;
-
-    var query = matchMedia("(prefers-reduced-motion:reduce)");
-
-    function mount() {
-      bind(query, "change", check);
-      check();
-    }
-
-    function check() {
-      var reduced = isReduced();
-      Components2.Options.fix("speed", reduced ? 0 : void 0);
-      reduced && Components2.Autoplay.pause();
-    }
-
-    function isReduced() {
-      return query.matches;
-    }
-
-    return {
-      mount: mount,
-      isReduced: isReduced
-    };
-  }
-
   var ComponentConstructors = /*#__PURE__*/Object.freeze({
     __proto__: null,
-    Options: Options,
+    Media: Media,
     Direction: Direction,
     Elements: Elements,
     Slides: Slides,
@@ -2776,8 +2745,7 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
     Pagination: Pagination,
     Sync: Sync,
     Wheel: Wheel,
-    Live: Live,
-    Motion: Motion
+    Live: Live
   });
   var I18N = {
     prev: "Previous slide",
@@ -2817,8 +2785,8 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
   };
 
   function Fade(Splide2, Components2, options) {
-    var _EventInterface19 = EventInterface(Splide2),
-        on = _EventInterface19.on;
+    var _EventInterface18 = EventInterface(Splide2),
+        on = _EventInterface18.on;
 
     function mount() {
       on([EVENT_MOUNTED, EVENT_REFRESH], function () {
@@ -2845,8 +2813,8 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
   }
 
   function Slide(Splide2, Components2, options) {
-    var _EventInterface20 = EventInterface(Splide2),
-        bind = _EventInterface20.bind;
+    var _EventInterface19 = EventInterface(Splide2),
+        bind = _EventInterface19.bind;
 
     var Move = Components2.Move,
         Controller = Components2.Controller;

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
dist/js/splide.min.js


BIN
dist/js/splide.min.js.gz


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
dist/js/splide.min.js.map


+ 132 - 111
dist/types/index.d.ts

@@ -1,60 +1,9 @@
 /**
- * The interface for the Arrows component.
- *
- * @since 3.0.0
- */
-interface ArrowsComponent extends BaseComponent {
-    arrows: {
-        prev?: HTMLButtonElement;
-        next?: HTMLButtonElement;
-    };
-}
-
-/**
- * The interface for the Autoplay component.
- *
- * @since 3.0.0
- */
-interface AutoplayComponent extends BaseComponent {
-    play(): void;
-    pause(): void;
-    isPaused(): boolean;
-}
-
-/**
- * The interface for the Clone component.
- *
- * @since 3.0.0
- */
-interface ClonesComponent extends BaseComponent {
-}
-
-/**
- * The interface for the Controller component.
- *
- * @since 3.0.0
- */
-interface ControllerComponent extends BaseComponent {
-    go(control: number | string, allowSameIndex?: boolean, callback?: AnyFunction): void;
-    scroll(destination: number, useIndex?: boolean, snap?: boolean, duration?: number, callback?: AnyFunction): void;
-    getNext(destination?: boolean): number;
-    getPrev(destination?: boolean): number;
-    getAdjacent(prev: boolean, destination?: boolean): number;
-    getEnd(): number;
-    setIndex(index: number): void;
-    getIndex(prev?: boolean): number;
-    toIndex(page: number): number;
-    toPage(index: number): number;
-    toDest(position: number): number;
-    hasFocus(): boolean;
-}
-
-/**
- * The interface for the Cover component.
+ * The interface for the Options component.
  *
  * @since 3.0.0
  */
-interface CoverComponent extends BaseComponent {
+interface MediaComponent extends BaseComponent {
 }
 
 /**
@@ -67,16 +16,6 @@ interface DirectionComponent extends BaseComponent {
     orient(value: number): number;
 }
 
-/**
- * The interface for the Drag component.
- *
- * @since 3.0.0
- */
-interface DragComponent extends BaseComponent {
-    disable(disabled: boolean): void;
-    isDragging(): boolean;
-}
-
 /**
  * The interface for elements which the slider consists of.
  *
@@ -104,28 +43,6 @@ interface ElementCollection {
 interface ElementsComponent extends BaseComponent, ElementCollection {
 }
 
-/**
- * The interface for the Keyboard component.
- *
- * @since 3.0.0
- */
-interface KeyboardComponent extends BaseComponent {
-    disable(disabled: boolean): void;
-}
-
-/**
- * The interface for the Layout component.
- *
- * @since 3.0.0
- */
-interface LayoutComponent extends BaseComponent {
-    listSize(): number;
-    slideSize(index: number, withoutGap?: boolean): number;
-    sliderSize(): number;
-    totalSize(index?: number, withoutGap?: boolean): number;
-    getPadding(right: boolean): number;
-}
-
 /**
  * The interface for the Slide sub component.
  *
@@ -143,20 +60,24 @@ interface SlideComponent extends BaseComponent {
 }
 
 /**
- * The interface for the LazyLoad component.
+ * The interface for the Layout component.
  *
  * @since 3.0.0
  */
-interface LazyLoadComponent extends BaseComponent {
+interface LayoutComponent extends BaseComponent {
+    listSize(): number;
+    slideSize(index: number, withoutGap?: boolean): number;
+    sliderSize(): number;
+    totalSize(index?: number, withoutGap?: boolean): number;
+    getPadding(right: boolean): number;
 }
 
 /**
- * The interface for the Live component.
+ * The interface for the Clone component.
  *
- * @since 3.7.0
+ * @since 3.0.0
  */
-interface LiveComponent extends BaseComponent {
-    disable(disabled: boolean): void;
+interface ClonesComponent extends BaseComponent {
 }
 
 /**
@@ -179,11 +100,91 @@ interface MoveComponent extends BaseComponent {
 }
 
 /**
- * The interface for the Options component.
+ * The interface for the Controller component.
+ *
+ * @since 3.0.0
+ */
+interface ControllerComponent extends BaseComponent {
+    go(control: number | string, allowSameIndex?: boolean, callback?: AnyFunction): void;
+    scroll(destination: number, useIndex?: boolean, snap?: boolean, duration?: number, callback?: AnyFunction): void;
+    getNext(destination?: boolean): number;
+    getPrev(destination?: boolean): number;
+    getAdjacent(prev: boolean, destination?: boolean): number;
+    getEnd(): number;
+    setIndex(index: number): void;
+    getIndex(prev?: boolean): number;
+    toIndex(page: number): number;
+    toPage(index: number): number;
+    toDest(position: number): number;
+    hasFocus(): boolean;
+}
+
+/**
+ * The interface for the Arrows component.
  *
  * @since 3.0.0
  */
-interface OptionsComponent extends BaseComponent {
+interface ArrowsComponent extends BaseComponent {
+    arrows: {
+        prev?: HTMLButtonElement;
+        next?: HTMLButtonElement;
+    };
+}
+
+/**
+ * The interface for the Autoplay component.
+ *
+ * @since 3.0.0
+ */
+interface AutoplayComponent extends BaseComponent {
+    play(): void;
+    pause(): void;
+    isPaused(): boolean;
+}
+
+/**
+ * The interface for the Cover component.
+ *
+ * @since 3.0.0
+ */
+interface CoverComponent extends BaseComponent {
+}
+
+/**
+ * The interface for the Scroll component.
+ *
+ * @since 3.0.0
+ */
+interface ScrollComponent extends BaseComponent {
+    scroll(position: number, duration?: number, callback?: AnyFunction): void;
+    cancel(): void;
+}
+
+/**
+ * The interface for the Drag component.
+ *
+ * @since 3.0.0
+ */
+interface DragComponent extends BaseComponent {
+    disable(disabled: boolean): void;
+    isDragging(): boolean;
+}
+
+/**
+ * The interface for the Keyboard component.
+ *
+ * @since 3.0.0
+ */
+interface KeyboardComponent extends BaseComponent {
+    disable(disabled: boolean): void;
+}
+
+/**
+ * The interface for the LazyLoad component.
+ *
+ * @since 3.0.0
+ */
+interface LazyLoadComponent extends BaseComponent {
 }
 
 /**
@@ -216,16 +217,6 @@ interface PaginationItem {
     page: number;
 }
 
-/**
- * The interface for the Scroll component.
- *
- * @since 3.0.0
- */
-interface ScrollComponent extends BaseComponent {
-    scroll(position: number, duration?: number, callback?: AnyFunction): void;
-    cancel(): void;
-}
-
 /**
  * The interface for the Sync component.
  *
@@ -243,6 +234,15 @@ interface SyncComponent extends BaseComponent {
 interface WheelComponent extends BaseComponent {
 }
 
+/**
+ * The interface for the Live component.
+ *
+ * @since 3.7.0
+ */
+interface LiveComponent extends BaseComponent {
+    disable(disabled: boolean): void;
+}
+
 /**
  * The collection of i18n strings.
  *
@@ -633,7 +633,7 @@ interface SyncTarget {
  */
 interface Components {
     [key: string]: BaseComponent;
-    Options: OptionsComponent;
+    Media: MediaComponent;
     Direction: DirectionComponent;
     Elements: ElementsComponent;
     Slides: SlidesComponent;
@@ -666,12 +666,10 @@ interface EventMap {
     'click': (Slide: SlideComponent, e: MouseEvent) => void;
     'move': (index: number, prev: number, dest: number) => void;
     'moved': (index: number, prev: number, dest: number) => void;
-    'shifted': () => void;
     'active': (Slide: SlideComponent) => void;
     'inactive': (Slide: SlideComponent) => void;
     'visible': (Slide: SlideComponent) => void;
     'hidden': (Slide: SlideComponent) => void;
-    'slide:keydown': (Slide: SlideComponent, e: KeyboardEvent) => void;
     'refresh': () => void;
     'updated': (options: Options) => void;
     'resize': () => void;
@@ -691,6 +689,10 @@ interface EventMap {
     'autoplay:playing': (rate: number) => void;
     'autoplay:pause': () => void;
     'lazyload:loaded': (img: HTMLImageElement, Slide: SlideComponent) => void;
+    /** @internal */
+    'shifted': () => void;
+    'slide:keydown': (Slide: SlideComponent, e: KeyboardEvent) => void;
+    'media': (query: MediaQueryList) => void;
 }
 
 /**
@@ -699,12 +701,24 @@ interface EventMap {
  * @internal
  */
 declare type Cast<T, U> = T extends U ? T : U;
+/**
+ * Makes the T easy to read.
+ */
+declare type Resolve<T> = {
+    [K in keyof T]: T[K];
+} & unknown;
 /**
  * Pushes U to tuple T.
  *
  * @internal
  */
 declare type Push<T extends any[], U = any> = [...T, U];
+/**
+ * Returns the first type of the tuple.
+ *
+ * @internal
+ */
+declare type Head<T extends any[]> = ((...args: T) => any) extends (arg: infer A, ...args: any[]) => any ? A : never;
 /**
  * Removes the first type from the tuple T.
  *
@@ -777,7 +791,6 @@ interface EventBusObject {
  * @since 3.0.0
  */
 interface EventHandler {
-    _event: string;
     _callback: AnyFunction;
     _namespace: string;
     _priority: number;
@@ -798,6 +811,12 @@ declare type EventBusCallback = AnyFunction;
  */
 declare function EventBus(): EventBusObject;
 
+/**
+ * The type for an EventTarget or an array with EventTarget objects.
+ *
+ * @since 3.7.0
+ */
+declare type EventTargets = EventTarget | EventTarget[];
 /**
  * The interface for the EventInterface object.
  *
@@ -809,8 +828,8 @@ interface EventInterfaceObject {
     off<K extends keyof EventMap>(events: K | K[] | string | string[]): void;
     emit<K extends keyof EventMap>(event: K, ...args: Parameters<EventMap[K]>): void;
     emit(event: string, ...args: any[]): void;
-    bind(target: Element | Window | Document | Array<Element | Window | Document>, events: string, callback: AnyFunction, options?: AddEventListenerOptions): void;
-    unbind(target: Element | Window | Document | Array<Element | Window | Document>, events: string, callback?: AnyFunction): void;
+    bind(target: EventTargets, events: string, callback: AnyFunction, options?: AddEventListenerOptions): void;
+    unbind(target: EventTarget | EventTarget[], events: string, callback?: AnyFunction): void;
     destroy(): void;
 }
 /**
@@ -819,10 +838,11 @@ interface EventInterfaceObject {
  * @since 3.0.0
  *
  * @param Splide - A Splide instance.
+ * @param manual - Optional. Whether to destroy the interface manually or not.
  *
  * @return A collection of interface functions.
  */
-declare function EventInterface(Splide: Splide): EventInterfaceObject;
+declare function EventInterface(Splide: Splide, manual?: boolean): EventInterfaceObject;
 
 /**
  * The interface for the returning value of the RequestInterval.
@@ -1520,6 +1540,7 @@ declare const EVENT_HIDDEN = "hidden";
 declare const EVENT_SLIDE_KEYDOWN = "slide:keydown";
 declare const EVENT_REFRESH = "refresh";
 declare const EVENT_UPDATED = "updated";
+declare const EVENT_MEDIA = "media";
 declare const EVENT_RESIZE = "resize";
 declare const EVENT_RESIZED = "resized";
 declare const EVENT_REPOSITIONED = "repositioned";
@@ -1588,4 +1609,4 @@ declare const CLASSES: {
     spinner: string;
 };
 
-export { AnyFunction, ArrowsComponent, AutoplayComponent, BaseComponent, CLASSES, CLASS_ACTIVE, CLASS_ARROW, CLASS_ARROWS, CLASS_ARROW_NEXT, CLASS_ARROW_PREV, CLASS_AUTOPLAY, CLASS_CLONE, CLASS_CONTAINER, CLASS_INITIALIZED, CLASS_LIST, CLASS_LOADING, CLASS_NEXT, CLASS_PAGINATION, CLASS_PAGINATION_PAGE, CLASS_PAUSE, CLASS_PLAY, CLASS_PREV, CLASS_PROGRESS, CLASS_PROGRESS_BAR, CLASS_ROOT, CLASS_SLIDE, CLASS_SLIDER, CLASS_SPINNER, CLASS_SR, CLASS_TRACK, CLASS_VISIBLE, Cast, ClonesComponent, ComponentConstructor, Components, ControllerComponent, CoverComponent, DirectionComponent, DragComponent, EVENT_ACTIVE, EVENT_ARROWS_MOUNTED, EVENT_ARROWS_UPDATED, EVENT_AUTOPLAY_PAUSE, EVENT_AUTOPLAY_PLAY, EVENT_AUTOPLAY_PLAYING, EVENT_CLICK, EVENT_DESTROY, EVENT_DRAG, EVENT_DRAGGED, EVENT_DRAGGING, EVENT_HIDDEN, EVENT_INACTIVE, EVENT_LAZYLOAD_LOADED, EVENT_MOUNTED, EVENT_MOVE, EVENT_MOVED, EVENT_NAVIGATION_MOUNTED, EVENT_PAGINATION_MOUNTED, EVENT_PAGINATION_UPDATED, EVENT_READY, EVENT_REFRESH, EVENT_REPOSITIONED, EVENT_RESIZE, EVENT_RESIZED, EVENT_SCROLL, EVENT_SCROLLED, EVENT_SHIFTED, EVENT_SLIDE_KEYDOWN, EVENT_UPDATED, EVENT_VISIBLE, ElementsComponent, EventBus, EventBusCallback, EventBusObject, EventHandler, EventInterface, EventInterfaceObject, EventMap, KeyboardComponent, LayoutComponent, LazyLoadComponent, LiveComponent, MoveComponent, Options, OptionsComponent, PaginationComponent, PaginationData, PaginationItem, Push, RequestInterval, RequestIntervalInterface, ResponsiveOptions, STATUS_CLASSES, ScrollComponent, Shift, ShiftN, SlideComponent, SlidesComponent, Splide, SplideRenderer, State, StateObject, SyncComponent, SyncTarget, Throttle, ThrottleInstance, TransitionComponent, WheelComponent, Splide as default };
+export { AnyFunction, ArrowsComponent, AutoplayComponent, BaseComponent, CLASSES, CLASS_ACTIVE, CLASS_ARROW, CLASS_ARROWS, CLASS_ARROW_NEXT, CLASS_ARROW_PREV, CLASS_AUTOPLAY, CLASS_CLONE, CLASS_CONTAINER, CLASS_INITIALIZED, CLASS_LIST, CLASS_LOADING, CLASS_NEXT, CLASS_PAGINATION, CLASS_PAGINATION_PAGE, CLASS_PAUSE, CLASS_PLAY, CLASS_PREV, CLASS_PROGRESS, CLASS_PROGRESS_BAR, CLASS_ROOT, CLASS_SLIDE, CLASS_SLIDER, CLASS_SPINNER, CLASS_SR, CLASS_TRACK, CLASS_VISIBLE, Cast, ClonesComponent, ComponentConstructor, Components, ControllerComponent, CoverComponent, DirectionComponent, DragComponent, EVENT_ACTIVE, EVENT_ARROWS_MOUNTED, EVENT_ARROWS_UPDATED, EVENT_AUTOPLAY_PAUSE, EVENT_AUTOPLAY_PLAY, EVENT_AUTOPLAY_PLAYING, EVENT_CLICK, EVENT_DESTROY, EVENT_DRAG, EVENT_DRAGGED, EVENT_DRAGGING, EVENT_HIDDEN, EVENT_INACTIVE, EVENT_LAZYLOAD_LOADED, EVENT_MEDIA, EVENT_MOUNTED, EVENT_MOVE, EVENT_MOVED, EVENT_NAVIGATION_MOUNTED, EVENT_PAGINATION_MOUNTED, EVENT_PAGINATION_UPDATED, EVENT_READY, EVENT_REFRESH, EVENT_REPOSITIONED, EVENT_RESIZE, EVENT_RESIZED, EVENT_SCROLL, EVENT_SCROLLED, EVENT_SHIFTED, EVENT_SLIDE_KEYDOWN, EVENT_UPDATED, EVENT_VISIBLE, ElementsComponent, EventBus, EventBusCallback, EventBusObject, EventHandler, EventInterface, EventInterfaceObject, EventMap, Head, KeyboardComponent, LayoutComponent, LazyLoadComponent, LiveComponent, MediaComponent, MoveComponent, Options, PaginationComponent, PaginationData, PaginationItem, Push, RequestInterval, RequestIntervalInterface, Resolve, ResponsiveOptions, STATUS_CLASSES, ScrollComponent, Shift, ShiftN, SlideComponent, SlidesComponent, Splide, SplideRenderer, State, StateObject, SyncComponent, SyncTarget, Throttle, ThrottleInstance, TransitionComponent, WheelComponent, Splide as default };

+ 3 - 0
jest.config.js

@@ -4,4 +4,7 @@ module.exports = {
     '^.+\\.(ts|tsx)$': 'ts-jest',
   },
   testEnvironment: 'jsdom',
+	setupFiles: [
+		'./js/test/jest/setup.ts',
+	],
 };

+ 3 - 8
src/js/components/Autoplay/Autoplay.ts

@@ -41,6 +41,7 @@ export function Autoplay( Splide: Splide, Components: Components, options: Optio
   const interval = RequestInterval( options.interval, Splide.go.bind( Splide, '>' ), update );
   const { isPaused } = interval;
   const { Elements } = Components;
+  const { autoplay } = options;
 
   /**
    * Indicates whether the slider is hovered or not.
@@ -55,22 +56,17 @@ export function Autoplay( Splide: Splide, Components: Components, options: Optio
   /**
    * Turns into `true` when autoplay is manually paused.
    */
-  let paused: boolean;
+  let paused = autoplay === 'pause';
 
   /**
    * Called when the component is mounted.
    */
   function mount(): void {
-    const { autoplay } = options;
-
     if ( autoplay ) {
       initButton( true );
       initButton( false );
       listen();
-
-      if ( autoplay !== 'pause' ) {
-        play();
-      }
+      ! paused && play();
     }
   }
 
@@ -86,7 +82,6 @@ export function Autoplay( Splide: Splide, Components: Components, options: Optio
     if ( button ) {
       setAttribute( button, ARIA_CONTROLS, Elements.track.id );
       setAttribute( button, ARIA_LABEL, options.i18n[ prop ] );
-
       bind( button, 'click', forPause ? pause : play );
     }
   }

+ 122 - 0
src/js/components/Media/Media.ts

@@ -0,0 +1,122 @@
+import { EVENT_MEDIA } from '../../constants/events';
+import { DESTROYED } from '../../constants/states';
+import { EventInterface } from '../../constructors';
+import { Splide } from '../../core/Splide/Splide';
+import { BaseComponent, Components, Options } from '../../types';
+import { find, merge, noop } from '../../utils';
+
+
+/**
+ * The interface for the Options component.
+ *
+ * @since 3.0.0
+ */
+export interface MediaComponent extends BaseComponent {
+}
+
+/**
+ * The component for observing media queries and update options if necessary.
+ *
+ * @since 3.0.0
+ *
+ * @param Splide     - A Splide instance.
+ * @param Components - A collection of components.
+ * @param options    - Options.
+ *
+ * @return A Media component object.
+ */
+export function Media( Splide: Splide, Components: Components, options: Options ): MediaComponent {
+  const event       = EventInterface( Splide, true );
+  const breakpoints = options.breakpoints || {};
+
+  /**
+   * Keeps the initial options to apply when no matched query exists.
+   */
+  const userOptions: Options = merge( {}, options );
+
+  /**
+   * Stores options and MediaQueryList object.
+   */
+  const queries: Array<[ Options, MediaQueryList? ][]> = [];
+
+  /**
+   * Called when the component is constructed.
+   */
+  function setup(): void {
+    const isMin = options.mediaQuery === 'min';
+
+    register( Object.keys( breakpoints )
+      .sort( ( n, m ) => isMin ? +m - +n : +n - +m )
+      .map<[ Options, string? ]>( key => [ breakpoints[ key ], `(${ isMin ? 'min' : 'max' }-width:${ key }px)` ] )
+      .concat( [ [ userOptions ] ] ) );
+
+    register( [ [ {
+      speed   : 0,
+      autoplay: 'pause',
+    }, '(prefers-reduced-motion: reduce)' ] ] );
+
+    update();
+  }
+
+  /**
+   * Destroys the component.
+   *
+   * @param completely - Will be `true` for complete destruction.
+   */
+  function destroy( completely: boolean ): void {
+    if ( completely ) {
+      event.destroy();
+    }
+  }
+
+  /**
+   * Registers entries as [ Options, media query string ].
+   *
+   * @param entries - An array with entries.
+   */
+  function register( entries: [ Options, string? ][] ): void {
+    queries.push( entries.map<[ Options, MediaQueryList? ]>( entry => {
+      const query = entry[ 1 ] && matchMedia( entry[ 1 ] );
+      query && event.bind( query, 'change', update );
+      return [ entry[ 0 ], query ];
+    } ) );
+  }
+
+  /**
+   * Checks all media queries in entries and updates options.
+   */
+  function update(): void {
+    const options = accumulate();
+    const { destroy: _destroy } = options;
+
+    if ( _destroy ) {
+      Splide.options = userOptions;
+      Splide.destroy( _destroy === 'completely' );
+    } else if ( Splide.state.is( DESTROYED ) ) {
+      destroy( true );
+      Splide.mount();
+    } else {
+      Splide.options = options;
+    }
+  }
+
+  /**
+   * Accumulates all options assigned to predefined media queries,
+   * and merges them into user options.
+   *
+   * @return Merged options.
+   */
+  function accumulate(): Options {
+    return queries.reduce<Options>( ( merged, entries ) => {
+      const entry = ( find( entries, entry => ! entry[ 1 ] || entry[ 1 ].matches ) || [] );
+      entry[ 1 ] && event.emit( EVENT_MEDIA, entry[ 1 ] );
+      return merge( merged, entry[ 0 ] || {} );
+    }, merge( {}, userOptions ) );
+  }
+
+  return {
+    setup,
+    mount: noop,
+    destroy,
+  };
+}

+ 48 - 0
src/js/components/Media/test/general.test.ts

@@ -0,0 +1,48 @@
+import { EVENT_MEDIA } from '../../../constants/events';
+import { DESTROYED } from '../../../constants/states';
+import { init } from '../../../test';
+
+
+describe( 'Options', () => {
+  beforeAll( () => {
+    window.matchMedia = () => ( {
+      matches            : true, // All queries match the media string.
+      media              : '',
+      onchange           : null,
+      addListener        : jest.fn(),
+      removeListener     : jest.fn(),
+      addEventListener   : jest.fn(),
+      removeEventListener: jest.fn(),
+      dispatchEvent      : jest.fn(),
+    } as MediaQueryList );
+  } );
+
+  test( 'can merge options when a breakpoint matches the media query.', () => {
+    const splide = init( { perPage: 2, breakpoints: { 640: { perPage: 4 } } } );
+    expect( splide.options.perPage ).toBe( 4 );
+  } );
+
+  test( 'can destroy Splide.', () => {
+    const splide = init( { breakpoints: { 640: { destroy: true } } } );
+    expect( splide.state.is( DESTROYED ) ).toBe( true );
+  } );
+
+  test( 'can merge options for prefers-reduced-motion:reduce.', () => {
+    const splide = init();
+    expect( splide.options.speed ).toBe( 0 );
+    expect( splide.options.autoplay ).toBe( 'pause' );
+  } );
+
+  test( 'can emit events when any media query changes.', () => {
+    const splide   = init( { breakpoints: { 640: { perPage: 4 } } }, { mount: false } );
+    const callback = jest.fn();
+
+    splide.on( EVENT_MEDIA, query => {
+      expect( query.matches ).toBe( true );
+      callback();
+    } );
+
+    splide.mount();
+    expect( callback ).toHaveBeenCalledTimes( 2 ); // a breakpoint and prefers-reduced-motion
+  } );
+} );

+ 0 - 62
src/js/components/Motion/Motion.ts

@@ -1,62 +0,0 @@
-import { EventInterface } from '../../constructors';
-import { Splide } from '../../core/Splide/Splide';
-import { BaseComponent, Components, Options } from '../../types';
-
-
-/**
- * The interface for the Motion component.
- *
- * @since 3.7.0
- */
-export interface MotionComponent extends BaseComponent {
-  isReduced(): boolean;
-}
-
-/**
- * The component to reduce non-essential motion if the user requests it.
- * This component does not work in IE since it does not support `prefers-reduced-motion`.
- *
- * @link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion
- *
- * @since 3.7.0
- *
- * @param Splide     - A Splide instance.
- * @param Components - A collection of components.
- * @param options    - Options.
- *
- * @return A Motion component object.
- */
-export function Motion( Splide: Splide, Components: Components, options: Options ): MotionComponent {
-  const { bind } = EventInterface( Splide );
-  const query = matchMedia( '(prefers-reduced-motion:reduce)' );
-
-  /**
-   * Called when the component is mounted.
-   * The event handler will never be fired on IE since it does not support `prefers-reduced-motion`.
-   */
-  function mount(): void {
-    bind( query, 'change', check );
-    check();
-  }
-
-  /**
-   * Checks the query and updates the slider if necessary.
-   */
-  function check(): void {
-    const reduced = isReduced();
-    Components.Options.fix( 'speed', reduced ? 0 : undefined );
-    reduced && Components.Autoplay.pause();
-  }
-
-  /**
-   * Checks if the motion should be reduced or not.
-   */
-  function isReduced(): boolean {
-    return query.matches;
-  }
-
-  return {
-    mount,
-    isReduced,
-  };
-}

+ 0 - 119
src/js/components/Options/Options.ts

@@ -1,119 +0,0 @@
-import { DESTROYED } from '../../constants/states';
-import { EventInterface } from '../../constructors';
-import { Splide } from '../../core/Splide/Splide';
-import { BaseComponent, Components, Options } from '../../types';
-import { find, isUndefined, merge, noop } from '../../utils';
-
-
-/**
- * The interface for the Options component.
- *
- * @since 3.0.0
- */
-export interface OptionsComponent extends BaseComponent {
-  fix<K extends keyof Options>( key: K, value?: Options[ K ] ): void;
-}
-
-/**
- * The component for managing options.
- *
- * @since 3.0.0
- *
- * @param Splide     - A Splide instance.
- * @param Components - A collection of components.
- * @param options    - Options.
- *
- * @return An Options component object.
- */
-export function Options( Splide: Splide, Components: Components, options: Options ): OptionsComponent {
-  const event = EventInterface( Splide, true );
-  const breakpoints = options.breakpoints || {};
-
-  /**
-   * Keeps the initial options to apply when no matched query exists.
-   */
-  const userOptions: Options = merge( {}, options );
-
-  /**
-   * Stores fixed options.
-   */
-  const fixedOptions: Options = {};
-
-  /**
-   * Stores breakpoints with the MediaQueryList object.
-   */
-  let points: [ string, MediaQueryList ][];
-
-  /**
-   * Called when the component is constructed.
-   */
-  function setup(): void {
-    const isMin = options.mediaQuery === 'min';
-
-    points = Object.keys( breakpoints )
-      .sort( ( n, m ) => isMin ? +m - +n : +n - +m )
-      .map( point => {
-        const queryList = matchMedia( `(${ isMin ? 'min' : 'max' }-width:${ point }px)` );
-        event.bind( queryList, 'change', check );
-        return [ point, queryList ];
-      } );
-
-    check();
-  }
-
-  /**
-   * Destroys the component.
-   *
-   * @param completely - Will be `true` for complete destruction.
-   */
-  function destroy( completely: boolean ): void {
-    if ( completely ) {
-      event.destroy();
-    }
-  }
-
-  /**
-   * Observes breakpoints.
-   */
-  function check(): void {
-    const point      = ( find( points, item => item[ 1 ].matches ) || [] )[ 0 ];
-    const newOptions = merge( {}, breakpoints[ point ] || userOptions, fixedOptions );
-
-    if ( newOptions.destroy ) {
-      Splide.options = userOptions;
-      Splide.destroy( newOptions.destroy === 'completely' );
-    } else {
-      if ( Splide.state.is( DESTROYED ) ) {
-        destroy( true );
-        Splide.mount();
-      } else {
-        Splide.options = newOptions;
-      }
-    }
-  }
-
-  /**
-   * Fixes options to prevent breakpoints from overwriting them.
-   *
-   * @param key   - A key.
-   * @param value - Optional. A value to fix. If omitted, the value will be restored.
-   */
-  function fix<K extends keyof Options>( key: K, value?: Options[ K ] ): void {
-    if ( fixedOptions[ key ] !== value ) {
-      if ( isUndefined( value ) ) {
-        delete fixedOptions[ key ];
-      } else {
-        fixedOptions[ key ] = value;
-      }
-
-      check();
-    }
-  }
-
-  return {
-    setup,
-    mount: noop,
-    destroy,
-    fix,
-  };
-}

+ 0 - 19
src/js/components/Options/test/general.test.ts

@@ -1,19 +0,0 @@
-import { DESTROYED } from '../../../constants/states';
-import { init } from '../../../test';
-
-
-describe( 'Options', () => {
-  window.matchMedia = () => ( {
-    matches: true,
-  } as MediaQueryList );
-
-  test( 'can merge options when a breakpoint matches the media query.', () => {
-    const splide = init( { perPage: 2, breakpoints: { 640: { perPage: 4 } } } );
-    expect( splide.options.perPage ).toBe( 4 );
-  } );
-
-  test( 'can destroy Splide.', () => {
-    const splide = init( { breakpoints: { 640: { destroy: true } } } );
-    expect( splide.state.is( DESTROYED ) ).toBe( true );
-  } );
-} );

+ 1 - 2
src/js/components/index.ts

@@ -1,4 +1,4 @@
-export { Options }    from './Options/Options';
+export { Media }      from './Media/Media';
 export { Direction }  from './Direction/Direction';
 export { Elements }   from './Elements/Elements';
 export { Slides }     from './Slides/Slides';
@@ -17,4 +17,3 @@ export { Pagination } from './Pagination/Pagination';
 export { Sync }       from './Sync/Sync';
 export { Wheel }      from './Wheel/Wheel';
 export { Live }       from './Live/Live';
-export { Motion }     from './Motion/Motion';

+ 1 - 2
src/js/components/types.ts

@@ -1,4 +1,4 @@
-export type { OptionsComponent }    from './Options/Options';
+export type { MediaComponent }      from './Media/Media';
 export type { DirectionComponent }  from './Direction/Direction';
 export type { ElementsComponent }   from './Elements/Elements';
 export type { SlidesComponent }     from './Slides/Slides';
@@ -18,6 +18,5 @@ export type { PaginationComponent } from './Pagination/Pagination';
 export type { SyncComponent }       from './Sync/Sync';
 export type { WheelComponent }      from './Wheel/Wheel';
 export type { LiveComponent }       from './Live/Live';
-export type { MotionComponent }     from './Motion/Motion';
 
 export type { PaginationData, PaginationItem } from './Pagination/Pagination';

+ 1 - 0
src/js/constants/events.ts

@@ -11,6 +11,7 @@ export const EVENT_HIDDEN             = 'hidden';
 export const EVENT_SLIDE_KEYDOWN      = 'slide:keydown';
 export const EVENT_REFRESH            = 'refresh';
 export const EVENT_UPDATED            = 'updated';
+export const EVENT_MEDIA              = 'media';
 export const EVENT_RESIZE             = 'resize';
 export const EVENT_RESIZED            = 'resized';
 export const EVENT_REPOSITIONED       = 'repositioned';

+ 1 - 5
src/js/constructors/EventBus/EventBus.ts

@@ -22,7 +22,6 @@ export interface EventBusObject {
  * @since 3.0.0
  */
 export interface EventHandler {
-  _event: string;
   _callback: AnyFunction;
   _namespace: string;
   _priority: number;
@@ -68,7 +67,6 @@ export function EventBus(): EventBusObject {
       handlers[ event ] = handlers[ event ] || [];
 
       push( handlers[ event ], {
-        _event    : event,
         _callback : callback,
         _namespace: namespace,
         _priority : priority,
@@ -87,9 +85,7 @@ export function EventBus(): EventBusObject {
    */
   function off( events: string | string[], key?: object ): void {
     forEachEvent( events, ( event, namespace ) => {
-      const eventHandlers = handlers[ event ];
-
-      handlers[ event ] = eventHandlers && eventHandlers.filter( handler => {
+      handlers[ event ] = ( handlers[ event ] || [] ).filter( handler => {
         return handler._key ? handler._key !== key : key || handler._namespace !== namespace;
       } );
     } );

+ 1 - 1
src/js/constructors/Throttle/Throttle.ts

@@ -28,10 +28,10 @@ export function Throttle<F extends AnyFunction>(
 
   function throttled( this: ThisParameterType<F> ): void {
     if ( ! interval ) {
+      // eslint-disable-next-line prefer-rest-params
       const args = slice( arguments );
 
       interval = RequestInterval( duration || 0, () => {
-        // eslint-disable-next-line prefer-rest-params
         func.apply( this, args );
         interval = null;
       }, null, 1 );

+ 10 - 0
src/js/test/jest/setup.ts

@@ -0,0 +1,10 @@
+window.matchMedia = () => ( {
+  matches            : false, // All queries match the media string.
+  media              : '',
+  onchange           : null,
+  addListener        : jest.fn(),
+  removeListener     : jest.fn(),
+  addEventListener   : jest.fn(),
+  removeEventListener: jest.fn(),
+  dispatchEvent      : jest.fn(),
+} as MediaQueryList );

+ 20 - 40
src/js/types/components.ts

@@ -1,23 +1,4 @@
-import { ArrowsComponent } from '../components/Arrows/Arrows';
-import { AutoplayComponent } from '../components/Autoplay/Autoplay';
-import { ClonesComponent } from '../components/Clones/Clones';
-import { ControllerComponent } from '../components/Controller/Controller';
-import { CoverComponent } from '../components/Cover/Cover';
-import { DirectionComponent } from '../components/Direction/Direction';
-import { DragComponent } from '../components/Drag/Drag';
-import { ElementsComponent } from '../components/Elements/Elements';
-import { KeyboardComponent } from '../components/Keyboard/Keyboard';
-import { LayoutComponent } from '../components/Layout/Layout';
-import { LazyLoadComponent } from '../components/LazyLoad/LazyLoad';
-import { LiveComponent } from '../components/Live/Live';
-import { MotionComponent } from '../components/Motion/Motion';
-import { MoveComponent } from '../components/Move/Move';
-import { OptionsComponent } from '../components/Options/Options';
-import { PaginationComponent } from '../components/Pagination/Pagination';
-import { ScrollComponent } from '../components/Scroll/Scroll';
-import { SlidesComponent } from '../components/Slides/Slides';
-import { SyncComponent } from '../components/Sync/Sync';
-import { WheelComponent } from '../components/Wheel/Wheel';
+import * as Types from '../components/types';
 import { BaseComponent, TransitionComponent } from './general';
 
 
@@ -28,25 +9,24 @@ import { BaseComponent, TransitionComponent } from './general';
  */
 export interface Components {
   [ key: string ]: BaseComponent;
-  Options: OptionsComponent;
-  Direction: DirectionComponent;
-  Elements: ElementsComponent;
-  Slides: SlidesComponent;
-  Layout: LayoutComponent;
-  Clones: ClonesComponent;
-  Move: MoveComponent;
-  Controller: ControllerComponent;
-  Arrows: ArrowsComponent;
-  Autoplay: AutoplayComponent;
-  Cover: CoverComponent;
-  Scroll: ScrollComponent;
-  Drag: DragComponent;
-  Keyboard: KeyboardComponent;
-  LazyLoad: LazyLoadComponent;
-  Pagination: PaginationComponent;
-  Sync: SyncComponent;
-  Wheel: WheelComponent;
-  Live: LiveComponent;
-  Motion: MotionComponent;
+  Media: Types.MediaComponent;
+  Direction: Types.DirectionComponent;
+  Elements: Types.ElementsComponent;
+  Slides: Types.SlidesComponent;
+  Layout: Types.LayoutComponent;
+  Clones: Types.ClonesComponent;
+  Move: Types.MoveComponent;
+  Controller: Types.ControllerComponent;
+  Arrows: Types.ArrowsComponent;
+  Autoplay: Types.AutoplayComponent;
+  Cover: Types.CoverComponent;
+  Scroll: Types.ScrollComponent;
+  Drag: Types.DragComponent;
+  Keyboard: Types.KeyboardComponent;
+  LazyLoad: Types.LazyLoadComponent;
+  Pagination: Types.PaginationComponent;
+  Sync: Types.SyncComponent;
+  Wheel: Types.WheelComponent;
+  Live: Types.LiveComponent;
   Transition: TransitionComponent;
 }

+ 5 - 2
src/js/types/events.ts

@@ -15,12 +15,10 @@ export interface EventMap {
   'click': ( Slide: SlideComponent, e: MouseEvent ) => void;
   'move': ( index: number, prev: number, dest: number ) => void;
   'moved': ( index: number, prev: number, dest: number ) => void;
-  'shifted': () => void;
   'active': ( Slide: SlideComponent ) => void;
   'inactive': ( Slide: SlideComponent ) => void;
   'visible': ( Slide: SlideComponent ) => void;
   'hidden': ( Slide: SlideComponent ) => void;
-  'slide:keydown': ( Slide: SlideComponent, e: KeyboardEvent ) => void;
   'refresh': () => void;
   'updated': ( options: Options ) => void;
   'resize': () => void;
@@ -40,4 +38,9 @@ export interface EventMap {
   'autoplay:playing': ( rate: number ) => void;
   'autoplay:pause': () => void;
   'lazyload:loaded': ( img: HTMLImageElement, Slide: SlideComponent ) => void;
+
+  /** @internal */
+  'shifted': () => void;
+  'slide:keydown': ( Slide: SlideComponent, e: KeyboardEvent ) => void;
+  'media': ( query: MediaQueryList ) => void;
 }

+ 1 - 1
src/js/utils/object/merge/merge.test.ts

@@ -29,7 +29,7 @@ describe( 'merge', () => {
     const source2 = { b: { d: '4', g: 6 }, h: [ 1, 2, 3 ] };
     const source3 = { h: [ 4, 5, 6 ], i: Infinity };
     const source4 = { a: '1' };
-    const merged  = merge( object, source1, source2, source3, source4 )
+    const merged  = merge( object, source1, source2, source3, source4 );
 
     expect( merged ).toStrictEqual( {
       a: '1',

+ 1 - 0
src/js/utils/object/merge/merge.ts

@@ -53,6 +53,7 @@ export function merge<T extends object, U extends object[]>(
  * @return A new object with merged properties.
  */
 export function merge<T extends object>( object: T ): any {
+  // eslint-disable-next-line prefer-rest-params
   slice( arguments ).forEach( source => {
     forOwn( source, ( value, key ) => {
       if ( isArray( value ) ) {

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.