Sfoglia il codice sorgente

Bug Fix: Prevent VoiceOver from announcing the SR field (#805).

Naotoshi Fujita 3 anni fa
parent
commit
d10447ab52

+ 12 - 5
dist/js/splide.cjs.js

@@ -1,6 +1,6 @@
 /*!
 /*!
  * Splide.js
  * Splide.js
- * Version  : 4.0.2
+ * Version  : 4.0.3
  * License  : MIT
  * License  : MIT
  * Copyright: 2022 Naotoshi Fujita
  * Copyright: 2022 Naotoshi Fujita
  */
  */
@@ -1530,7 +1530,7 @@ function Move(Splide2, Components2, options) {
 
 
   function canShift(backwards) {
   function canShift(backwards) {
     var shifted = orient(shift(getPosition(), backwards));
     var shifted = orient(shift(getPosition(), backwards));
-    return backwards ? shifted >= 0 : shifted <= list["scroll" + resolve("Width")] - rect(track)[resolve("width")];
+    return backwards ? shifted >= 0 : shifted <= list[resolve("scrollWidth")] - rect(track)[resolve("width")];
   }
   }
 
 
   function exceededLimit(max, position) {
   function exceededLimit(max, position) {
@@ -2751,14 +2751,16 @@ function Wheel(Splide2, Components2, options) {
   };
   };
 }
 }
 
 
+var SR_REMOVAL_DELAY = 50;
+
 function Live(Splide2, Components2, options) {
 function Live(Splide2, Components2, options) {
   var _EventInterface14 = EventInterface(Splide2),
   var _EventInterface14 = EventInterface(Splide2),
       on = _EventInterface14.on;
       on = _EventInterface14.on;
 
 
   var track = Components2.Elements.track;
   var track = Components2.Elements.track;
-  var live = options.live;
-  var enabled = live && !options.isNavigation;
+  var enabled = options.live && !options.isNavigation;
   var sr = create("span", CLASS_SR);
   var sr = create("span", CLASS_SR);
+  var timer;
 
 
   function mount() {
   function mount() {
     if (enabled) {
     if (enabled) {
@@ -2767,7 +2769,12 @@ function Live(Splide2, Components2, options) {
       sr.textContent = "\u2026";
       sr.textContent = "\u2026";
       on(EVENT_AUTOPLAY_PLAY, apply(disable, true));
       on(EVENT_AUTOPLAY_PLAY, apply(disable, true));
       on(EVENT_AUTOPLAY_PAUSE, apply(disable, false));
       on(EVENT_AUTOPLAY_PAUSE, apply(disable, false));
-      on([EVENT_MOVED, EVENT_SCROLLED], apply(append, track, sr));
+      on([EVENT_MOVED, EVENT_SCROLLED], function () {
+        setAttribute(sr, ARIA_HIDDEN, false);
+        append(track, sr);
+        timer && clearTimeout(timer);
+        timer = setTimeout(setAttribute, SR_REMOVAL_DELAY, sr, ARIA_HIDDEN, true);
+      });
     }
     }
   }
   }
 
 

+ 12 - 5
dist/js/splide.esm.js

@@ -4,7 +4,7 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
 
 
 /*!
 /*!
  * Splide.js
  * Splide.js
- * Version  : 4.0.2
+ * Version  : 4.0.3
  * License  : MIT
  * License  : MIT
  * Copyright: 2022 Naotoshi Fujita
  * Copyright: 2022 Naotoshi Fujita
  */
  */
@@ -1525,7 +1525,7 @@ function Move(Splide2, Components2, options) {
 
 
   function canShift(backwards) {
   function canShift(backwards) {
     var shifted = orient(shift(getPosition(), backwards));
     var shifted = orient(shift(getPosition(), backwards));
-    return backwards ? shifted >= 0 : shifted <= list["scroll" + resolve("Width")] - rect(track)[resolve("width")];
+    return backwards ? shifted >= 0 : shifted <= list[resolve("scrollWidth")] - rect(track)[resolve("width")];
   }
   }
 
 
   function exceededLimit(max, position) {
   function exceededLimit(max, position) {
@@ -2746,14 +2746,16 @@ function Wheel(Splide2, Components2, options) {
   };
   };
 }
 }
 
 
+var SR_REMOVAL_DELAY = 50;
+
 function Live(Splide2, Components2, options) {
 function Live(Splide2, Components2, options) {
   var _EventInterface14 = EventInterface(Splide2),
   var _EventInterface14 = EventInterface(Splide2),
       on = _EventInterface14.on;
       on = _EventInterface14.on;
 
 
   var track = Components2.Elements.track;
   var track = Components2.Elements.track;
-  var live = options.live;
-  var enabled = live && !options.isNavigation;
+  var enabled = options.live && !options.isNavigation;
   var sr = create("span", CLASS_SR);
   var sr = create("span", CLASS_SR);
+  var timer;
 
 
   function mount() {
   function mount() {
     if (enabled) {
     if (enabled) {
@@ -2762,7 +2764,12 @@ function Live(Splide2, Components2, options) {
       sr.textContent = "\u2026";
       sr.textContent = "\u2026";
       on(EVENT_AUTOPLAY_PLAY, apply(disable, true));
       on(EVENT_AUTOPLAY_PLAY, apply(disable, true));
       on(EVENT_AUTOPLAY_PAUSE, apply(disable, false));
       on(EVENT_AUTOPLAY_PAUSE, apply(disable, false));
-      on([EVENT_MOVED, EVENT_SCROLLED], apply(append, track, sr));
+      on([EVENT_MOVED, EVENT_SCROLLED], function () {
+        setAttribute(sr, ARIA_HIDDEN, false);
+        append(track, sr);
+        timer && clearTimeout(timer);
+        timer = setTimeout(setAttribute, SR_REMOVAL_DELAY, sr, ARIA_HIDDEN, true);
+      });
     }
     }
   }
   }
 
 

+ 11 - 4
dist/js/splide.js

@@ -4,7 +4,7 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
 
 
 /*!
 /*!
  * Splide.js
  * Splide.js
- * Version  : 4.0.2
+ * Version  : 4.0.3
  * License  : MIT
  * License  : MIT
  * Copyright: 2022 Naotoshi Fujita
  * Copyright: 2022 Naotoshi Fujita
  */
  */
@@ -2744,14 +2744,16 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
     };
     };
   }
   }
 
 
+  var SR_REMOVAL_DELAY = 50;
+
   function Live(Splide2, Components2, options) {
   function Live(Splide2, Components2, options) {
     var _EventInterface14 = EventInterface(Splide2),
     var _EventInterface14 = EventInterface(Splide2),
         on = _EventInterface14.on;
         on = _EventInterface14.on;
 
 
     var track = Components2.Elements.track;
     var track = Components2.Elements.track;
-    var live = options.live;
-    var enabled = live && !options.isNavigation;
+    var enabled = options.live && !options.isNavigation;
     var sr = create("span", CLASS_SR);
     var sr = create("span", CLASS_SR);
+    var timer;
 
 
     function mount() {
     function mount() {
       if (enabled) {
       if (enabled) {
@@ -2760,7 +2762,12 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
         sr.textContent = "\u2026";
         sr.textContent = "\u2026";
         on(EVENT_AUTOPLAY_PLAY, apply(disable, true));
         on(EVENT_AUTOPLAY_PLAY, apply(disable, true));
         on(EVENT_AUTOPLAY_PAUSE, apply(disable, false));
         on(EVENT_AUTOPLAY_PAUSE, apply(disable, false));
-        on([EVENT_MOVED, EVENT_SCROLLED], apply(append, track, sr));
+        on([EVENT_MOVED, EVENT_SCROLLED], function () {
+          setAttribute(sr, ARIA_HIDDEN, false);
+          append(track, sr);
+          timer && clearTimeout(timer);
+          timer = setTimeout(setAttribute, SR_REMOVAL_DELAY, sr, ARIA_HIDDEN, true);
+        });
       }
       }
     }
     }
 
 

File diff suppressed because it is too large
+ 0 - 0
dist/js/splide.min.js


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


File diff suppressed because it is too large
+ 0 - 0
dist/js/splide.min.js.map


+ 2 - 2
package-lock.json

@@ -1,12 +1,12 @@
 {
 {
   "name": "@splidejs/splide",
   "name": "@splidejs/splide",
-  "version": "4.0.2",
+  "version": "4.0.3",
   "lockfileVersion": 2,
   "lockfileVersion": 2,
   "requires": true,
   "requires": true,
   "packages": {
   "packages": {
     "": {
     "": {
       "name": "@splidejs/splide",
       "name": "@splidejs/splide",
-      "version": "4.0.2",
+      "version": "4.0.3",
       "license": "MIT",
       "license": "MIT",
       "devDependencies": {
       "devDependencies": {
         "@babel/core": "^7.16.10",
         "@babel/core": "^7.16.10",

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@splidejs/splide",
   "name": "@splidejs/splide",
-  "version": "4.0.2",
+  "version": "4.0.3",
   "description": "Splide is a lightweight, flexible and accessible slider/carousel. No dependencies, no Lighthouse errors.",
   "description": "Splide is a lightweight, flexible and accessible slider/carousel. No dependencies, no Lighthouse errors.",
   "author": "Naotoshi Fujita",
   "author": "Naotoshi Fujita",
   "license": "MIT",
   "license": "MIT",

+ 21 - 5
src/js/components/Live/Live.ts

@@ -1,4 +1,4 @@
-import { ARIA_LIVE, ARIA_RELEVANT } from '../../constants/attributes';
+import { ARIA_HIDDEN, ARIA_LIVE, ARIA_RELEVANT } from '../../constants/attributes';
 import { CLASS_SR } from '../../constants/classes';
 import { CLASS_SR } from '../../constants/classes';
 import { EVENT_AUTOPLAY_PAUSE, EVENT_AUTOPLAY_PLAY, EVENT_MOVED, EVENT_SCROLLED } from '../../constants/events';
 import { EVENT_AUTOPLAY_PAUSE, EVENT_AUTOPLAY_PLAY, EVENT_MOVED, EVENT_SCROLLED } from '../../constants/events';
 import { EventInterface } from '../../constructors';
 import { EventInterface } from '../../constructors';
@@ -16,6 +16,11 @@ export interface LiveComponent extends BaseComponent {
   disable( disabled: boolean ): void;
   disable( disabled: boolean ): void;
 }
 }
 
 
+/**
+ * Delay in milliseconds before removing the SR field for Windows Narrator.
+ */
+const SR_REMOVAL_DELAY = 50;
+
 /**
 /**
  * The component for implementing Live Region to the slider.
  * The component for implementing Live Region to the slider.
  *
  *
@@ -32,21 +37,26 @@ export interface LiveComponent extends BaseComponent {
 export function Live( Splide: Splide, Components: Components, options: Options ): LiveComponent {
 export function Live( Splide: Splide, Components: Components, options: Options ): LiveComponent {
   const { on } = EventInterface( Splide );
   const { on } = EventInterface( Splide );
   const { track } = Components.Elements;
   const { track } = Components.Elements;
-  const { live } = options;
 
 
   /**
   /**
    * Indicates whether the live region is enabled or not.
    * Indicates whether the live region is enabled or not.
    */
    */
-  const enabled = live && ! options.isNavigation;
+  const enabled = options.live && ! options.isNavigation;
 
 
   /**
   /**
    * The span element for the SR only text.
    * The span element for the SR only text.
    */
    */
   const sr = create( 'span', CLASS_SR );
   const sr = create( 'span', CLASS_SR );
 
 
+  /**
+   * Keeps the timer ID.
+   */
+  let timer: number;
+
   /**
   /**
    * Called when the component is mounted.
    * Called when the component is mounted.
-   * The `aria-relevant` attribute is important to prevent SR from reading contents twice.
+   * - The `aria-relevant` attribute is important to prevent NVDA from reading contents twice
+   * - Immediately assigning `aria-hidden` makes Windows Narrator silent, hence requires the delay around 50ms.
    */
    */
   function mount(): void {
   function mount(): void {
     if ( enabled ) {
     if ( enabled ) {
@@ -56,7 +66,13 @@ export function Live( Splide: Splide, Components: Components, options: Options )
 
 
       on( EVENT_AUTOPLAY_PLAY, apply( disable, true ) );
       on( EVENT_AUTOPLAY_PLAY, apply( disable, true ) );
       on( EVENT_AUTOPLAY_PAUSE, apply( disable, false ) );
       on( EVENT_AUTOPLAY_PAUSE, apply( disable, false ) );
-      on( [ EVENT_MOVED, EVENT_SCROLLED ], apply( append, track, sr ) );
+
+      on( [ EVENT_MOVED, EVENT_SCROLLED ], () => {
+        setAttribute( sr, ARIA_HIDDEN, false );
+        append( track, sr );
+        timer && clearTimeout( timer );
+        timer = setTimeout( setAttribute, SR_REMOVAL_DELAY, sr, ARIA_HIDDEN, true );
+      } );
     }
     }
   }
   }
 
 

+ 1 - 1
src/js/constants/attributes.ts

@@ -17,7 +17,7 @@ export const ARIA_RELEVANT        = `${ ARIA_PREFIX }relevant`;
 /**
 /**
  * The array with all attributes to remove later.
  * The array with all attributes to remove later.
  * Need to manually remove attributes that are not in this.
  * Need to manually remove attributes that are not in this.
- * Note that removing aria-live disables the live region until the page reload.
+ * Note that removing `aria-live` disables the live region until the page reload.
  *
  *
  * @since 3.0.0
  * @since 3.0.0
  */
  */

Some files were not shown because too many files changed in this diff