浏览代码

Set focus to the active slide when the user clicks the pagination dot.

NaotoshiFujita 3 年之前
父节点
当前提交
72f56dbf2e

+ 23 - 24
dist/js/splide.cjs.js

@@ -1201,7 +1201,7 @@ function Move(Splide2, Components2, options) {
       jump(Splide2.index);
     }
   }
-  function move(dest, index, prev) {
+  function move(dest, index, prev, callback) {
     if (!isBusy()) {
       const { set } = Splide2.state;
       const position = getPosition();
@@ -1215,7 +1215,9 @@ function Move(Splide2, Components2, options) {
         set(IDLE);
         emit(EVENT_MOVED, index, prev, dest);
         if (options.trimSpace === "move" && dest !== prev && position === getPosition()) {
-          Components2.Controller.go(dest > prev ? ">" : "<");
+          Components2.Controller.go(dest > prev ? ">" : "<", false, callback);
+        } else {
+          callback && callback();
         }
       });
     }
@@ -1286,7 +1288,7 @@ function Move(Splide2, Components2, options) {
     return abs(position - toPosition(toIndex(position), true)) < SNAP_THRESHOLD;
   }
   function isBusy() {
-    return waiting;
+    return !!waiting;
   }
   function exceededLimit(max, position) {
     position = isUndefined(position) ? getPosition() : position;
@@ -1312,6 +1314,7 @@ function Move(Splide2, Components2, options) {
 function Controller(Splide2, Components2, options) {
   const { on } = EventInterface(Splide2);
   const { Move } = Components2;
+  const { jump, getPosition, getLimit } = Move;
   const { isEnough, getLength } = Components2.Slides;
   const isLoop = Splide2.is(LOOP);
   let currIndex = options.start || 0;
@@ -1321,7 +1324,7 @@ function Controller(Splide2, Components2, options) {
   let perPage;
   function mount() {
     init();
-    Move.jump(currIndex);
+    jump(currIndex);
     on([EVENT_UPDATED, EVENT_REFRESH], init);
     on(EVENT_SCROLLED, reindex, 0);
   }
@@ -1330,17 +1333,17 @@ function Controller(Splide2, Components2, options) {
     perMove = options.perMove;
     perPage = options.perPage;
     currIndex = min(currIndex, slideCount - 1);
-    Move.jump(currIndex);
+    jump(currIndex);
   }
   function reindex() {
-    setIndex(Move.toIndex(Move.getPosition()));
+    setIndex(Move.toIndex(getPosition()));
   }
-  function go(control, allowSameIndex) {
+  function go(control, allowSameIndex, callback) {
     const dest = parse(control);
     const index = loop(dest);
     if (index > -1 && !Move.isBusy() && (allowSameIndex || index !== currIndex)) {
       setIndex(index);
-      Move.move(dest, index, prevIndex);
+      Move.move(dest, index, prevIndex, callback);
     }
   }
   function parse(control) {
@@ -1373,16 +1376,8 @@ function Controller(Splide2, Components2, options) {
     const number = perMove || hasFocus() ? 1 : perPage;
     const dest = computeDestIndex(currIndex + number * (prev ? -1 : 1), currIndex);
     if (dest === -1 && Splide2.is(SLIDE)) {
-      const { getLimit } = Move;
-      const position = Move.getPosition();
-      if (prev) {
-        if (!approximatelyEqual(position, getLimit(false), 1)) {
-          return 0;
-        }
-      } else {
-        if (!approximatelyEqual(position, getLimit(true), 1)) {
-          return getEnd();
-        }
+      if (!approximatelyEqual(getPosition(), getLimit(!prev), 1)) {
+        return prev ? 0 : getEnd();
       }
     }
     return destination ? dest : loop(dest);
@@ -2028,8 +2023,8 @@ function LazyLoad(Splide2, Components2, options) {
 
 function Pagination(Splide2, Components2, options) {
   const { on, emit, bind, unbind } = EventInterface(Splide2);
-  const { Slides, Elements } = Components2;
-  const { go, toPage, hasFocus, getIndex } = Components2.Controller;
+  const { Slides, Elements, Controller } = Components2;
+  const { hasFocus, getIndex } = Controller;
   const items = [];
   let list;
   function mount() {
@@ -2066,16 +2061,20 @@ function Pagination(Splide2, Components2, options) {
       const button = create("button", { class: classes.page, type: "button" }, li);
       const controls = Slides.getIn(i).map((Slide) => Slide.slide.id);
       const text = !hasFocus() && perPage > 1 ? i18n.pageX : i18n.slideX;
-      bind(button, "click", () => {
-        go(`>${i}`, true);
-      });
+      bind(button, "click", onClick.bind(null, i));
       setAttribute(button, ARIA_CONTROLS, controls.join(" "));
       setAttribute(button, ARIA_LABEL, format(text, i + 1));
       items.push({ li, button, page: i });
     }
   }
+  function onClick(page) {
+    Controller.go(`>${page}`, true, () => {
+      const Slide = Slides.getAt(Controller.toIndex(page));
+      Slide && Slide.slide.focus();
+    });
+  }
   function getAt(index) {
-    return items[toPage(index)];
+    return items[Controller.toPage(index)];
   }
   function update() {
     const prev = getAt(getIndex(true));

+ 23 - 24
dist/js/splide.esm.js

@@ -1197,7 +1197,7 @@ function Move(Splide2, Components2, options) {
       jump(Splide2.index);
     }
   }
-  function move(dest, index, prev) {
+  function move(dest, index, prev, callback) {
     if (!isBusy()) {
       const { set } = Splide2.state;
       const position = getPosition();
@@ -1211,7 +1211,9 @@ function Move(Splide2, Components2, options) {
         set(IDLE);
         emit(EVENT_MOVED, index, prev, dest);
         if (options.trimSpace === "move" && dest !== prev && position === getPosition()) {
-          Components2.Controller.go(dest > prev ? ">" : "<");
+          Components2.Controller.go(dest > prev ? ">" : "<", false, callback);
+        } else {
+          callback && callback();
         }
       });
     }
@@ -1282,7 +1284,7 @@ function Move(Splide2, Components2, options) {
     return abs(position - toPosition(toIndex(position), true)) < SNAP_THRESHOLD;
   }
   function isBusy() {
-    return waiting;
+    return !!waiting;
   }
   function exceededLimit(max, position) {
     position = isUndefined(position) ? getPosition() : position;
@@ -1308,6 +1310,7 @@ function Move(Splide2, Components2, options) {
 function Controller(Splide2, Components2, options) {
   const { on } = EventInterface(Splide2);
   const { Move } = Components2;
+  const { jump, getPosition, getLimit } = Move;
   const { isEnough, getLength } = Components2.Slides;
   const isLoop = Splide2.is(LOOP);
   let currIndex = options.start || 0;
@@ -1317,7 +1320,7 @@ function Controller(Splide2, Components2, options) {
   let perPage;
   function mount() {
     init();
-    Move.jump(currIndex);
+    jump(currIndex);
     on([EVENT_UPDATED, EVENT_REFRESH], init);
     on(EVENT_SCROLLED, reindex, 0);
   }
@@ -1326,17 +1329,17 @@ function Controller(Splide2, Components2, options) {
     perMove = options.perMove;
     perPage = options.perPage;
     currIndex = min(currIndex, slideCount - 1);
-    Move.jump(currIndex);
+    jump(currIndex);
   }
   function reindex() {
-    setIndex(Move.toIndex(Move.getPosition()));
+    setIndex(Move.toIndex(getPosition()));
   }
-  function go(control, allowSameIndex) {
+  function go(control, allowSameIndex, callback) {
     const dest = parse(control);
     const index = loop(dest);
     if (index > -1 && !Move.isBusy() && (allowSameIndex || index !== currIndex)) {
       setIndex(index);
-      Move.move(dest, index, prevIndex);
+      Move.move(dest, index, prevIndex, callback);
     }
   }
   function parse(control) {
@@ -1369,16 +1372,8 @@ function Controller(Splide2, Components2, options) {
     const number = perMove || hasFocus() ? 1 : perPage;
     const dest = computeDestIndex(currIndex + number * (prev ? -1 : 1), currIndex);
     if (dest === -1 && Splide2.is(SLIDE)) {
-      const { getLimit } = Move;
-      const position = Move.getPosition();
-      if (prev) {
-        if (!approximatelyEqual(position, getLimit(false), 1)) {
-          return 0;
-        }
-      } else {
-        if (!approximatelyEqual(position, getLimit(true), 1)) {
-          return getEnd();
-        }
+      if (!approximatelyEqual(getPosition(), getLimit(!prev), 1)) {
+        return prev ? 0 : getEnd();
       }
     }
     return destination ? dest : loop(dest);
@@ -2024,8 +2019,8 @@ function LazyLoad(Splide2, Components2, options) {
 
 function Pagination(Splide2, Components2, options) {
   const { on, emit, bind, unbind } = EventInterface(Splide2);
-  const { Slides, Elements } = Components2;
-  const { go, toPage, hasFocus, getIndex } = Components2.Controller;
+  const { Slides, Elements, Controller } = Components2;
+  const { hasFocus, getIndex } = Controller;
   const items = [];
   let list;
   function mount() {
@@ -2062,16 +2057,20 @@ function Pagination(Splide2, Components2, options) {
       const button = create("button", { class: classes.page, type: "button" }, li);
       const controls = Slides.getIn(i).map((Slide) => Slide.slide.id);
       const text = !hasFocus() && perPage > 1 ? i18n.pageX : i18n.slideX;
-      bind(button, "click", () => {
-        go(`>${i}`, true);
-      });
+      bind(button, "click", onClick.bind(null, i));
       setAttribute(button, ARIA_CONTROLS, controls.join(" "));
       setAttribute(button, ARIA_LABEL, format(text, i + 1));
       items.push({ li, button, page: i });
     }
   }
+  function onClick(page) {
+    Controller.go(`>${page}`, true, () => {
+      const Slide = Slides.getAt(Controller.toIndex(page));
+      Slide && Slide.slide.focus();
+    });
+  }
   function getAt(index) {
-    return items[toPage(index)];
+    return items[Controller.toPage(index)];
   }
   function update() {
     const prev = getAt(getIndex(true));

+ 28 - 33
dist/js/splide.js

@@ -1441,7 +1441,7 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
       }
     }
 
-    function move(dest, index, prev) {
+    function move(dest, index, prev, callback) {
       if (!isBusy()) {
         var set = Splide2.state.set;
         var position = getPosition();
@@ -1456,7 +1456,9 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
           emit(EVENT_MOVED, index, prev, dest);
 
           if (options.trimSpace === "move" && dest !== prev && position === getPosition()) {
-            Components2.Controller.go(dest > prev ? ">" : "<");
+            Components2.Controller.go(dest > prev ? ">" : "<", false, callback);
+          } else {
+            callback && callback();
           }
         });
       }
@@ -1575,6 +1577,9 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
         on = _EventInterface7.on;
 
     var Move = Components2.Move;
+    var jump = Move.jump,
+        getPosition = Move.getPosition,
+        getLimit = Move.getLimit;
     var _Components2$Slides = Components2.Slides,
         isEnough = _Components2$Slides.isEnough,
         getLength = _Components2$Slides.getLength;
@@ -1587,7 +1592,7 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
 
     function mount() {
       init();
-      Move.jump(currIndex);
+      jump(currIndex);
       on([EVENT_UPDATED, EVENT_REFRESH], init);
       on(EVENT_SCROLLED, reindex, 0);
     }
@@ -1597,20 +1602,20 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
       perMove = options.perMove;
       perPage = options.perPage;
       currIndex = min(currIndex, slideCount - 1);
-      Move.jump(currIndex);
+      jump(currIndex);
     }
 
     function reindex() {
-      setIndex(Move.toIndex(Move.getPosition()));
+      setIndex(Move.toIndex(getPosition()));
     }
 
-    function go(control, allowSameIndex) {
+    function go(control, allowSameIndex, callback) {
       var dest = parse(control);
       var index = loop(dest);
 
       if (index > -1 && !Move.isBusy() && (allowSameIndex || index !== currIndex)) {
         setIndex(index);
-        Move.move(dest, index, prevIndex);
+        Move.move(dest, index, prevIndex, callback);
       }
     }
 
@@ -1653,17 +1658,8 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
       var dest = computeDestIndex(currIndex + number * (prev ? -1 : 1), currIndex);
 
       if (dest === -1 && Splide2.is(SLIDE)) {
-        var getLimit = Move.getLimit;
-        var position = Move.getPosition();
-
-        if (prev) {
-          if (!approximatelyEqual(position, getLimit(false), 1)) {
-            return 0;
-          }
-        } else {
-          if (!approximatelyEqual(position, getLimit(true), 1)) {
-            return getEnd();
-          }
+        if (!approximatelyEqual(getPosition(), getLimit(!prev), 1)) {
+          return prev ? 0 : getEnd();
         }
       }
 
@@ -2483,12 +2479,10 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
         unbind = _EventInterface15.unbind;
 
     var Slides = Components2.Slides,
-        Elements = Components2.Elements;
-    var _Components2$Controll = Components2.Controller,
-        go = _Components2$Controll.go,
-        toPage = _Components2$Controll.toPage,
-        hasFocus = _Components2$Controll.hasFocus,
-        getIndex = _Components2$Controll.getIndex;
+        Elements = Components2.Elements,
+        Controller = Components2.Controller;
+    var hasFocus = Controller.hasFocus,
+        getIndex = Controller.getIndex;
     var items = [];
     var list;
 
@@ -2531,7 +2525,7 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
       var max = hasFocus() ? length : ceil(length / perPage);
       list = create("ul", classes.pagination, parent);
 
-      var _loop = function _loop(i) {
+      for (var i = 0; i < max; i++) {
         var li = create("li", null, list);
         var button = create("button", {
           class: classes.page,
@@ -2541,9 +2535,7 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
           return Slide.slide.id;
         });
         var text = !hasFocus() && perPage > 1 ? i18n.pageX : i18n.slideX;
-        bind(button, "click", function () {
-          go(">" + i, true);
-        });
+        bind(button, "click", onClick.bind(null, i));
         setAttribute(button, ARIA_CONTROLS, controls.join(" "));
         setAttribute(button, ARIA_LABEL, format(text, i + 1));
         items.push({
@@ -2551,15 +2543,18 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
           button: button,
           page: i
         });
-      };
-
-      for (var i = 0; i < max; i++) {
-        _loop(i);
       }
     }
 
+    function onClick(page) {
+      Controller.go(">" + page, true, function () {
+        var Slide = Slides.getAt(Controller.toIndex(page));
+        Slide && Slide.slide.focus();
+      });
+    }
+
     function getAt(index) {
-      return items[toPage(index)];
+      return items[Controller.toPage(index)];
     }
 
     function update() {

文件差异内容过多而无法显示
+ 0 - 0
dist/js/splide.js.map


文件差异内容过多而无法显示
+ 1 - 1
dist/js/splide.min.js


二进制
dist/js/splide.min.js.gz


+ 2 - 2
dist/types/components/Controller/Controller.d.ts

@@ -1,12 +1,12 @@
 import { Splide } from '../../core/Splide/Splide';
-import { BaseComponent, Components, Options } from '../../types';
+import { AnyFunction, BaseComponent, Components, Options } from '../../types';
 /**
  * The interface for the Controller component.
  *
  * @since 3.0.0
  */
 export interface ControllerComponent extends BaseComponent {
-    go(control: number | string, allowSameIndex?: boolean): void;
+    go(control: number | string, allowSameIndex?: boolean, callback?: AnyFunction): void;
     getNext(destination?: boolean): number;
     getPrev(destination?: boolean): number;
     getEnd(): number;

+ 1 - 1
dist/types/components/Controller/Controller.d.ts.map

@@ -1 +1 @@
-{"version":3,"file":"Controller.d.ts","sourceRoot":"","sources":["Controller.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAIjE;;;;GAIG;AACH,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACxD,EAAE,CAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,cAAc,CAAC,EAAE,OAAO,GAAI,IAAI,CAAC;IAC/D,OAAO,CAAE,WAAW,CAAC,EAAE,OAAO,GAAI,MAAM,CAAC;IACzC,OAAO,CAAE,WAAW,CAAC,EAAE,OAAO,GAAI,MAAM,CAAC;IACzC,MAAM,IAAI,MAAM,CAAC;IACjB,QAAQ,CAAE,KAAK,EAAE,MAAM,GAAI,IAAI,CAAC;IAChC,QAAQ,CAAE,IAAI,CAAC,EAAE,OAAO,GAAI,MAAM,CAAC;IACnC,OAAO,CAAE,IAAI,EAAE,MAAM,GAAI,MAAM,CAAC;IAChC,MAAM,CAAE,KAAK,EAAE,MAAM,GAAI,MAAM,CAAC;IAChC,QAAQ,IAAI,OAAO,CAAC;CACrB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAI,mBAAmB,CA8S1G"}
+{"version":3,"file":"Controller.d.ts","sourceRoot":"","sources":["Controller.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI9E;;;;GAIG;AACH,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACxD,EAAE,CAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,cAAc,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,WAAW,GAAI,IAAI,CAAC;IACvF,OAAO,CAAE,WAAW,CAAC,EAAE,OAAO,GAAI,MAAM,CAAC;IACzC,OAAO,CAAE,WAAW,CAAC,EAAE,OAAO,GAAI,MAAM,CAAC;IACzC,MAAM,IAAI,MAAM,CAAC;IACjB,QAAQ,CAAE,KAAK,EAAE,MAAM,GAAI,IAAI,CAAC;IAChC,QAAQ,CAAE,IAAI,CAAC,EAAE,OAAO,GAAI,MAAM,CAAC;IACnC,OAAO,CAAE,IAAI,EAAE,MAAM,GAAI,MAAM,CAAC;IAChC,MAAM,CAAE,KAAK,EAAE,MAAM,GAAI,MAAM,CAAC;IAChC,QAAQ,IAAI,OAAO,CAAC;CACrB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAI,mBAAmB,CAiT1G"}

+ 2 - 2
dist/types/components/Move/Move.d.ts

@@ -1,12 +1,12 @@
 import { Splide } from '../../core/Splide/Splide';
-import { BaseComponent, Components, Options } from '../../types';
+import { AnyFunction, BaseComponent, Components, Options } from '../../types';
 /**
  * The interface for the Move component.
  *
  * @since 3.0.0
  */
 export interface MoveComponent extends BaseComponent {
-    move(dest: number, index: number, prev: number): void;
+    move(dest: number, index: number, prev: number, callback?: AnyFunction): void;
     jump(index: number): void;
     translate(position: number): void;
     cancel(): void;

+ 1 - 1
dist/types/components/Move/Move.d.ts.map

@@ -1 +1 @@
-{"version":3,"file":"Move.d.ts","sourceRoot":"","sources":["Move.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAKjE;;;;GAIG;AACH,MAAM,WAAW,aAAc,SAAQ,aAAa;IAClD,IAAI,CAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAI,IAAI,CAAC;IACxD,IAAI,CAAE,KAAK,EAAE,MAAM,GAAI,IAAI,CAAC;IAC5B,SAAS,CAAE,QAAQ,EAAE,MAAM,GAAI,IAAI,CAAC;IACpC,MAAM,IAAI,IAAI,CAAC;IACf,OAAO,CAAE,QAAQ,EAAE,MAAM,GAAI,MAAM,CAAC;IACpC,UAAU,CAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAI,MAAM,CAAC;IACxD,WAAW,IAAI,MAAM,CAAC;IACtB,QAAQ,CAAE,GAAG,EAAE,OAAO,GAAI,MAAM,CAAC;IACjC,MAAM,IAAI,OAAO,CAAC;IAClB,aAAa,CAAE,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAI,OAAO,CAAC;CACxE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAI,aAAa,CAgQ9F"}
+{"version":3,"file":"Move.d.ts","sourceRoot":"","sources":["Move.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAK9E;;;;GAIG;AACH,MAAM,WAAW,aAAc,SAAQ,aAAa;IAClD,IAAI,CAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,WAAW,GAAI,IAAI,CAAC;IAChF,IAAI,CAAE,KAAK,EAAE,MAAM,GAAI,IAAI,CAAC;IAC5B,SAAS,CAAE,QAAQ,EAAE,MAAM,GAAI,IAAI,CAAC;IACpC,MAAM,IAAI,IAAI,CAAC;IACf,OAAO,CAAE,QAAQ,EAAE,MAAM,GAAI,MAAM,CAAC;IACpC,UAAU,CAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAI,MAAM,CAAC;IACxD,WAAW,IAAI,MAAM,CAAC;IACtB,QAAQ,CAAE,GAAG,EAAE,OAAO,GAAI,MAAM,CAAC;IACjC,MAAM,IAAI,OAAO,CAAC;IAClB,aAAa,CAAE,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAI,OAAO,CAAC;CACxE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAI,aAAa,CAmQ9F"}

+ 1 - 1
dist/types/components/Pagination/Pagination.d.ts.map

@@ -1 +1 @@
-{"version":3,"file":"Pagination.d.ts","sourceRoot":"","sources":["Pagination.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAIjE;;;;GAIG;AACH,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACxD,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,KAAK,CAAE,KAAK,EAAE,MAAM,GAAI,cAAc,CAAC;CACxC;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,aAAa,CAAC;IAClB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAI,mBAAmB,CAgH1G"}
+{"version":3,"file":"Pagination.d.ts","sourceRoot":"","sources":["Pagination.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAIjE;;;;GAIG;AACH,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACxD,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,KAAK,CAAE,KAAK,EAAE,MAAM,GAAI,cAAc,CAAC;CACxC;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,aAAa,CAAC;IAClB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAI,mBAAmB,CA4H1G"}

+ 17 - 0
src/js/components/Arrows/test/slide.test.ts

@@ -1,3 +1,4 @@
+import { EVENT_MOVED } from '../../../constants/events';
 import { fire, init } from '../../../test';
 
 
@@ -37,6 +38,22 @@ describe( 'Arrows', () => {
     expect( next.disabled ).toBe( true );
   } );
 
+  test( 'should not disable arrows if the slider position is not approximately same with each limit.', () => {
+    splide.go( 0 );
+
+    expect( prev.disabled ).toBe( true );
+    expect( next.disabled ).toBe( false );
+
+    splide.Components.Move.translate( -10 );
+    splide.emit( EVENT_MOVED );
+
+    // Index should be still 0
+    expect( splide.index ).toBe( 0 );
+
+    expect( prev.disabled ).toBe( false );
+    expect( next.disabled ).toBe( false );
+  } );
+
   test( 'can update aria attributes.', () => {
     expect( prev.getAttribute( 'aria-label' ) ).toBe( i18n.prev );
     expect( next.getAttribute( 'aria-label' ) ).toBe( i18n.next );

+ 11 - 19
src/js/components/Controller/Controller.ts

@@ -2,7 +2,7 @@ import { EVENT_REFRESH, EVENT_SCROLLED, EVENT_UPDATED } from '../../constants/ev
 import { LOOP, SLIDE } from '../../constants/types';
 import { EventInterface } from '../../constructors';
 import { Splide } from '../../core/Splide/Splide';
-import { BaseComponent, Components, Options } from '../../types';
+import { AnyFunction, BaseComponent, Components, Options } from '../../types';
 import { approximatelyEqual, between, clamp, floor, isString, isUndefined, max, min } from '../../utils';
 
 
@@ -12,7 +12,7 @@ import { approximatelyEqual, between, clamp, floor, isString, isUndefined, max,
  * @since 3.0.0
  */
 export interface ControllerComponent extends BaseComponent {
-  go( control: number | string, allowSameIndex?: boolean ): void;
+  go( control: number | string, allowSameIndex?: boolean, callback?: AnyFunction ): void;
   getNext( destination?: boolean ): number;
   getPrev( destination?: boolean ): number;
   getEnd(): number;
@@ -37,6 +37,7 @@ export interface ControllerComponent extends BaseComponent {
 export function Controller( Splide: Splide, Components: Components, options: Options ): ControllerComponent {
   const { on } = EventInterface( Splide );
   const { Move } = Components;
+  const { jump, getPosition, getLimit } = Move;
   const { isEnough, getLength } = Components.Slides;
   const isLoop = Splide.is( LOOP );
 
@@ -70,7 +71,7 @@ export function Controller( Splide: Splide, Components: Components, options: Opt
    */
   function mount(): void {
     init();
-    Move.jump( currIndex );
+    jump( currIndex );
     on( [ EVENT_UPDATED, EVENT_REFRESH ], init );
     on( EVENT_SCROLLED, reindex, 0 );
   }
@@ -84,15 +85,14 @@ export function Controller( Splide: Splide, Components: Components, options: Opt
     perMove    = options.perMove;
     perPage    = options.perPage;
     currIndex  = min( currIndex, slideCount - 1 );
-
-    Move.jump( currIndex );
+    jump( currIndex );
   }
 
   /**
    * Calculates the index by the current position and updates the current index.
    */
   function reindex(): void {
-    setIndex( Move.toIndex( Move.getPosition() ) );
+    setIndex( Move.toIndex( getPosition() ) );
   }
 
   /**
@@ -102,14 +102,15 @@ export function Controller( Splide: Splide, Components: Components, options: Opt
    *
    * @param control        - A control pattern.
    * @param allowSameIndex - Optional. Determines whether to allow to go to the current index or not.
+   * @param callback       - Optional. A callback function invoked after transition ends.
    */
-  function go( control: number | string, allowSameIndex?: boolean ): void {
+  function go( control: number | string, allowSameIndex?: boolean, callback?: AnyFunction ): void {
     const dest  = parse( control );
     const index = loop( dest );
 
     if ( index > -1 && ! Move.isBusy() && ( allowSameIndex || index !== currIndex ) ) {
       setIndex( index );
-      Move.move( dest, index, prevIndex );
+      Move.move( dest, index, prevIndex, callback );
     }
   }
 
@@ -177,17 +178,8 @@ export function Controller( Splide: Splide, Components: Components, options: Opt
     const dest   = computeDestIndex( currIndex + number * ( prev ? -1 : 1 ), currIndex );
 
     if ( dest === -1 && Splide.is( SLIDE ) ) {
-      const { getLimit } = Move;
-      const position = Move.getPosition();
-
-      if ( prev ) {
-        if ( ! approximatelyEqual( position, getLimit( false ), 1 ) ) {
-          return 0;
-        }
-      } else {
-        if ( ! approximatelyEqual( position, getLimit( true ), 1 ) ) {
-          return getEnd();
-        }
+      if ( ! approximatelyEqual( getPosition(), getLimit( ! prev ), 1 ) ) {
+        return prev ? 0 : getEnd();
       }
     }
 

+ 10 - 7
src/js/components/Move/Move.ts

@@ -4,7 +4,7 @@ import { IDLE, MOVING } from '../../constants/states';
 import { FADE, LOOP, SLIDE } from '../../constants/types';
 import { EventInterface } from '../../constructors';
 import { Splide } from '../../core/Splide/Splide';
-import { BaseComponent, Components, Options } from '../../types';
+import { AnyFunction, BaseComponent, Components, Options } from '../../types';
 import { abs, clamp, isUndefined, rect } from '../../utils';
 import { SNAP_THRESHOLD } from './constants';
 
@@ -15,7 +15,7 @@ import { SNAP_THRESHOLD } from './constants';
  * @since 3.0.0
  */
 export interface MoveComponent extends BaseComponent {
-  move( dest: number, index: number, prev: number ): void;
+  move( dest: number, index: number, prev: number, callback?: AnyFunction ): void;
   jump( index: number ): void;
   translate( position: number ): void;
   cancel(): void;
@@ -78,11 +78,12 @@ export function Move( Splide: Splide, Components: Components, options: Options )
   /**
    * Moves the slider to the dest index with the Transition component.
    *
-   * @param dest  - A destination index to go to, including clones'.
-   * @param index - A slide index.
-   * @param prev  - A previous index.
+   * @param dest     - A destination index to go to, including clones'.
+   * @param index    - A slide index.
+   * @param prev     - A previous index.
+   * @param callback - Optional. A callback function invoked after transition ends.
    */
-  function move( dest: number, index: number, prev: number ): void {
+  function move( dest: number, index: number, prev: number, callback?: AnyFunction ): void {
     if ( ! isBusy() ) {
       const { set } = Splide.state;
       const position = getPosition();
@@ -99,7 +100,9 @@ export function Move( Splide: Splide, Components: Components, options: Options )
         emit( EVENT_MOVED, index, prev, dest );
 
         if ( options.trimSpace === 'move' && dest !== prev && position === getPosition() ) {
-          Components.Controller.go( dest > prev ? '>' : '<' );
+          Components.Controller.go( dest > prev ? '>' : '<', false, callback );
+        } else {
+          callback && callback();
         }
       } );
     }

+ 19 - 4
src/js/components/Pagination/Pagination.ts

@@ -48,8 +48,8 @@ export interface PaginationItem {
  */
 export function Pagination( Splide: Splide, Components: Components, options: Options ): PaginationComponent {
   const { on, emit, bind, unbind } = EventInterface( Splide );
-  const { Slides, Elements } = Components;
-  const { go, toPage, hasFocus, getIndex } = Components.Controller;
+  const { Slides, Elements, Controller } = Components;
+  const { hasFocus, getIndex } = Controller;
 
   /**
    * Stores all pagination items.
@@ -112,7 +112,7 @@ export function Pagination( Splide: Splide, Components: Components, options: Opt
       const controls = Slides.getIn( i ).map( Slide => Slide.slide.id );
       const text     = ! hasFocus() && perPage > 1 ? i18n.pageX : i18n.slideX;
 
-      bind( button, 'click', () => { go( `>${ i }`, true ) } );
+      bind( button, 'click', onClick.bind( null, i ) );
 
       setAttribute( button, ARIA_CONTROLS, controls.join( ' ' ) );
       setAttribute( button, ARIA_LABEL, format( text, i + 1 ) );
@@ -121,6 +121,21 @@ export function Pagination( Splide: Splide, Components: Components, options: Opt
     }
   }
 
+  /**
+   * Called when the user clicks each pagination dot.
+   * Moves the focus to the active slide for accessibility.
+   *
+   * @link https://www.w3.org/WAI/tutorials/carousels/functionality/
+   *
+   * @param page - A clicked page index.
+   */
+  function onClick( page: number ): void {
+    Controller.go( `>${ page }`, true, () => {
+      const Slide = Slides.getAt( Controller.toIndex( page ) );
+      Slide && Slide.slide.focus();
+    } );
+  }
+
   /**
    * Returns the pagination item at the specified index.
    *
@@ -129,7 +144,7 @@ export function Pagination( Splide: Splide, Components: Components, options: Opt
    * @return A pagination item object if available, or otherwise `undefined`.
    */
   function getAt( index: number ): PaginationItem | undefined {
-    return items[ toPage( index ) ];
+    return items[ Controller.toPage( index ) ];
   }
 
   /**

+ 11 - 0
src/js/components/Pagination/test/general.test.ts

@@ -68,6 +68,17 @@ describe( 'Pagination', () => {
     expect( items[ 3 ].getAttribute( 'aria-current' ) ).toBe( 'true' );
   } );
 
+  test( 'can set focus to the selected slide.', () => {
+    const splide = init( { speed: 0 } );
+    const items  = document.getElementsByClassName( CLASS_PAGINATION_PAGE );
+
+    fire( items[ 0 ], 'click' );
+    expect( splide.Components.Slides.getAt( 0 ).slide ).toBe( document.activeElement );
+
+    fire( items[ 1 ], 'click' );
+    expect( splide.Components.Slides.getAt( 1).slide ).toBe( document.activeElement );
+  } );
+
   test( 'should not create pagination if slides are not enough to the perPage option.', () => {
     init( { perPage: 3 }, { length: 1 } );
     const items  = document.getElementsByClassName( CLASS_PAGINATION_PAGE );

+ 4 - 0
src/js/test/assets/css/styles.css

@@ -22,6 +22,10 @@ img {
   border: 2px solid deepskyblue;
 }
 
+.splide__slide:focus, .splide__arrow:focus, .splide__pagination__page:focus {
+  border: 2px solid tomato;
+}
+
 .splide__pagination__page.is-active {
   background: deepskyblue;
 }

+ 0 - 1
src/js/test/php/examples/default.php

@@ -23,7 +23,6 @@ $settings = get_settings();
         perPage: 3,
         // perMove: 1,
         gap    : '1.5rem',
-        // drag   : 'free',
         height : 200,
       } );
 

+ 37 - 0
src/js/test/php/examples/drag-free.php

@@ -0,0 +1,37 @@
+<?php
+require_once '../parts.php';
+require_once '../settings.php';
+
+$settings = get_settings();
+?>
+
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+  <title>Drag Free</title>
+
+  <link rel="stylesheet" href="../../../../../dist/css/themes/splide-<?php echo $settings['theme'] ?>.min.css">
+  <link rel="stylesheet" href="../../assets/css/styles.css">
+  <script type="text/javascript" src="../../../../../dist/js/splide.js"></script>
+
+  <script>
+    document.addEventListener( 'DOMContentLoaded', function () {
+      var splide = new Splide( '#splide01', {
+        perPage: 3,
+        gap    : '1.5rem',
+        drag   : 'free',
+        height : 200,
+      } );
+
+      splide.mount();
+    } );
+  </script>
+</head>
+<body>
+
+<?php render(); ?>
+
+</body>
+</html>

部分文件因为文件数量过多而无法显示