Explorar el Código

Improving accessibility for synced sliders.

NaotoshiFujita hace 3 años
padre
commit
d78a7f1c4f

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
dist/css/splide.min.css


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
dist/css/themes/splide-default.min.css


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
dist/css/themes/splide-sea-green.min.css


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
dist/css/themes/splide-skyblue.min.css


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
dist/js/splide-renderer.min.js


+ 25 - 24
dist/js/splide.js

@@ -2553,7 +2553,6 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
     }
 
     function destroy() {
-      removeAttribute(list, ALL_ATTRIBUTES);
       events.forEach(function (event) {
         event.destroy();
       });
@@ -2653,9 +2652,10 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
 
     var list = Components2.Elements.list;
     var live = options.live;
+    var enabled = live && !options.isNavigation;
 
     function mount() {
-      if (live) {
+      if (enabled) {
         setAttribute(list, ARIA_ATOMIC, false);
         disable(!Components2.Autoplay.isPaused());
         on(EVENT_AUTOPLAY_PLAY, apply(disable, true));
@@ -2664,7 +2664,7 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
     }
 
     function disable(disabled) {
-      if (live) {
+      if (enabled) {
         setAttribute(list, ARIA_LIVE, disabled ? "off" : "polite");
       }
     }
@@ -2730,6 +2730,7 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
     slideFocus: true,
     trimSpace: true,
     focusableNodes: "a, button, textarea, input, select, iframe",
+    live: true,
     classes: CLASSES,
     i18n: I18N
   };
@@ -2831,8 +2832,8 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
       this.Components = {};
       this.state = State(CREATED);
       this.splides = [];
-      this._o = {};
-      this._E = {};
+      this._options = {};
+      this._Extensions = {};
       var root = isString(target) ? query(document, target) : target;
       assert(root, root + " is invalid.");
       this.root = root;
@@ -2844,7 +2845,7 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
         assert(false, "Invalid JSON");
       }
 
-      this._o = options;
+      this._options = options;
     }
 
     var _proto = _Splide.prototype;
@@ -2856,14 +2857,14 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
           Components2 = this.Components;
       assert(state.is([CREATED, DESTROYED]), "Already mounted!");
       state.set(CREATED);
-      this._C = Components2;
-      this._T = Transition || this._T || (this.is(FADE) ? Fade : Slide);
-      this._E = Extensions || this._E;
-      var Constructors = assign({}, ComponentConstructors, this._E, {
-        Transition: this._T
+      this._Components = Components2;
+      this._Transition = Transition || this._Transition || (this.is(FADE) ? Fade : Slide);
+      this._Extensions = Extensions || this._Extensions;
+      var Constructors = assign({}, ComponentConstructors, this._Extensions, {
+        Transition: this._Transition
       });
       forOwn(Constructors, function (Component, key) {
-        var component = Component(_this2, Components2, _this2._o);
+        var component = Component(_this2, Components2, _this2._options);
         Components2[key] = component;
         component.setup && component.setup();
       });
@@ -2887,7 +2888,7 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
       });
 
       if (this.state.is(IDLE)) {
-        this._C.Sync.remount();
+        this._Components.Sync.remount();
 
         splide.Components.Sync.remount();
       }
@@ -2896,7 +2897,7 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
     };
 
     _proto.go = function go(control) {
-      this._C.Controller.go(control);
+      this._Components.Controller.go(control);
 
       return this;
     };
@@ -2920,19 +2921,19 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
     };
 
     _proto.add = function add(slides, index) {
-      this._C.Slides.add(slides, index);
+      this._Components.Slides.add(slides, index);
 
       return this;
     };
 
     _proto.remove = function remove(matcher) {
-      this._C.Slides.remove(matcher);
+      this._Components.Slides.remove(matcher);
 
       return this;
     };
 
     _proto.is = function is(type) {
-      return this._o.type === type;
+      return this._options.type === type;
     };
 
     _proto.refresh = function refresh() {
@@ -2951,7 +2952,7 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
       if (state.is(CREATED)) {
         EventInterface(this).on(EVENT_READY, this.destroy.bind(this, completely));
       } else {
-        forOwn(this._C, function (component) {
+        forOwn(this._Components, function (component) {
           component.destroy && component.destroy(completely);
         }, true);
         event.emit(EVENT_DESTROY);
@@ -2966,25 +2967,25 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
     _createClass(_Splide, [{
       key: "options",
       get: function get() {
-        return this._o;
+        return this._options;
       },
       set: function set(options) {
-        var _o = this._o;
-        merge(_o, options);
+        var _options = this._options;
+        merge(_options, options);
 
         if (!this.state.is(CREATED)) {
-          this.emit(EVENT_UPDATED, _o);
+          this.emit(EVENT_UPDATED, _options);
         }
       }
     }, {
       key: "length",
       get: function get() {
-        return this._C.Slides.getLength(true);
+        return this._Components.Slides.getLength(true);
       }
     }, {
       key: "index",
       get: function get() {
-        return this._C.Controller.getIndex();
+        return this._Components.Controller.getIndex();
       }
     }]);
 

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
dist/js/splide.min.js


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


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
dist/js/splide.min.js.map


+ 1 - 1
src/css/template/default/foundation/colors.scss

@@ -5,4 +5,4 @@ $sub02: #999 !default;
 $background: #ccc !default;
 $background-active: #fff !default;
 
-$focus: $main !default;
+$focus: #00bbff !default;

+ 8 - 2
src/css/template/default/foundation/mixins.scss

@@ -1,9 +1,15 @@
 @use './colors';
 
-$outline: colors.$focus 2px solid !default;
-$outline-offset: 2px !default;
+$outline: colors.$focus 3px solid !default;
+$outline-offset: 3px !default;
+$outline-offset-slide: -3px !default;
 
 @mixin focus-outline {
   outline: $outline;
   outline-offset: $outline-offset;
+}
+
+@mixin focus-outline-slide {
+  @include focus-outline;
+  outline-offset: $outline-offset-slide;
 }

+ 5 - 0
src/css/template/default/object/modifiers/nav.scss

@@ -1,4 +1,5 @@
 @use '../../foundation/colors';
+@use '../../foundation/mixins';
 
 $border: 3px solid transparent !default;
 $border-active: 3px solid colors.$main !default;
@@ -36,6 +37,10 @@ $opacity-active: false !default;
           &:focus {
             outline: none;
           }
+
+          &:focus-visible {
+            @include mixins.focus-outline-slide;
+          }
         }
       }
     }

+ 1 - 2
src/css/template/default/object/objects/slide.scss

@@ -11,8 +11,7 @@ $outline-offset: -2px !default;
     }
 
     &:focus-visible {
-      @include mixins.focus-outline;
-      outline-offset: $outline-offset;
+      @include mixins.focus-outline-slide;
     }
   }
 }

+ 2 - 0
src/css/themes/sea-green/index.scss

@@ -7,6 +7,7 @@ $main-light: lighten( $main, 20% ) !default;
   $sub02: $main,
   $background: #ccc,
   $background-active: $main,
+  $focus: $main,
 );
 
 @use '../../template/default/object/modifiers/nav' with (
@@ -28,6 +29,7 @@ $main-light: lighten( $main, 20% ) !default;
   $fill-hover: $main-light,
   $transition: fill .2s linear,
   $button-size: 2.5em,
+  $button-border-radius: 0,
   $button-background: transparent,
 );
 

+ 3 - 1
src/css/themes/skyblue/index.scss

@@ -6,7 +6,8 @@ $main-light: lighten( $main, 20% ) !default;
   $sub01: $main,
   $sub02: $main,
   $background: #ccc,
-  $background-active: $main
+  $background-active: $main,
+  $focus: $main,
 );
 
 @use '../../template/default/object/modifiers/nav' with (
@@ -21,6 +22,7 @@ $main-light: lighten( $main, 20% ) !default;
   $fill-hover: $main-light,
   $transition: fill .2s linear,
   $button-size: 2.5em,
+  $button-border-radius: 0,
   $button-background: transparent,
 );
 

+ 7 - 2
src/js/components/Live/Live.ts

@@ -33,6 +33,11 @@ export function Live( Splide: Splide, Components: Components, options: Options )
   const { list } = Components.Elements;
   const { live } = options;
 
+  /**
+   * Indicates whether the live region is enabled or not.
+   */
+  const enabled = live && ! options.isNavigation;
+
   /**
    * Called when the component is mounted.
    * Explicitly sets `aria-atomic` to avoid SR from reading the content twice.
@@ -40,7 +45,7 @@ export function Live( Splide: Splide, Components: Components, options: Options )
    * @link https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-atomic
    */
   function mount(): void {
-    if ( live ) {
+    if ( enabled ) {
       setAttribute( list, ARIA_ATOMIC, false );
       disable( ! Components.Autoplay.isPaused() );
       on( EVENT_AUTOPLAY_PLAY, apply( disable, true ) );
@@ -55,7 +60,7 @@ export function Live( Splide: Splide, Components: Components, options: Options )
    * @param disabled - `true` to disable the live region or `false` to enable it again.
    */
   function disable( disabled: boolean ): void {
-    if ( live ) {
+    if ( enabled ) {
       setAttribute( list, ARIA_LIVE, disabled ? 'off' : 'polite' );
     }
   }

+ 2 - 3
src/js/components/Sync/Sync.ts

@@ -1,4 +1,4 @@
-import { ALL_ATTRIBUTES, ARIA_ORIENTATION, ROLE } from '../../constants/attributes';
+import { ARIA_ORIENTATION, ROLE } from '../../constants/attributes';
 import { TTB } from '../../constants/directions';
 import {
   EVENT_CLICK,
@@ -12,7 +12,7 @@ import { LOOP } from '../../constants/types';
 import { EventInterface, EventInterfaceObject } from '../../constructors';
 import { Splide } from '../../core/Splide/Splide';
 import { BaseComponent, Components, Options } from '../../types';
-import { empty, includes, prevent, removeAttribute, setAttribute } from '../../utils';
+import { empty, includes, prevent, setAttribute } from '../../utils';
 import { SlideComponent } from '../Slides/Slide';
 
 
@@ -64,7 +64,6 @@ export function Sync( Splide: Splide, Components: Components, options: Options )
    * Destroys the component.
    */
   function destroy(): void {
-    removeAttribute( list, ALL_ATTRIBUTES );
     events.forEach( event => { event.destroy() } );
     empty( events );
   }

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

@@ -29,6 +29,7 @@ export const DEFAULTS: Options = {
   slideFocus       : true,
   trimSpace        : true,
   focusableNodes   : 'a, button, textarea, input, select, iframe',
+  live             : true,
   classes          : CLASSES,
   i18n             : I18N,
 };

+ 22 - 22
src/js/core/Splide/Splide.ts

@@ -56,22 +56,22 @@ export class Splide {
   /**
    * The collection of options.
    */
-  private readonly _o: Options = {};
+  private readonly _options: Options = {};
 
   /**
    * The collection of all components.
    */
-  private _C: Components;
+  private _Components: Components;
 
   /**
    * The collection of extensions.
    */
-  private _E: Record<string, ComponentConstructor> = {};
+  private _Extensions: Record<string, ComponentConstructor> = {};
 
   /**
    * The Transition component.
    */
-  private _T: ComponentConstructor;
+  private _Transition: ComponentConstructor;
 
   /**
    * The Splide constructor.
@@ -93,7 +93,7 @@ export class Splide {
       assert( false, 'Invalid JSON' );
     }
 
-    this._o = options;
+    this._options = options;
   }
 
   /**
@@ -110,14 +110,14 @@ export class Splide {
 
     state.set( CREATED );
 
-    this._C = Components;
-    this._T = Transition || this._T || ( this.is( FADE ) ? Fade : Slide );
-    this._E = Extensions || this._E;
+    this._Components = Components;
+    this._Transition = Transition || this._Transition || ( this.is( FADE ) ? Fade : Slide );
+    this._Extensions = Extensions || this._Extensions;
 
-    const Constructors = assign( {}, ComponentConstructors, this._E, { Transition: this._T } );
+    const Constructors = assign( {}, ComponentConstructors, this._Extensions, { Transition: this._Transition } );
 
     forOwn( Constructors, ( Component, key ) => {
-      const component = Component( this, Components, this._o );
+      const component = Component( this, Components, this._options );
       Components[ key ] = component;
       component.setup && component.setup();
     } );
@@ -159,7 +159,7 @@ export class Splide {
     splide.splides.push( { splide: this, isParent: true } );
 
     if ( this.state.is( IDLE ) ) {
-      this._C.Sync.remount();
+      this._Components.Sync.remount();
       splide.Components.Sync.remount();
     }
 
@@ -203,7 +203,7 @@ export class Splide {
    * @return `this`
    */
   go( control: number | string ): this {
-    this._C.Controller.go( control );
+    this._Components.Controller.go( control );
     return this;
   }
 
@@ -297,7 +297,7 @@ export class Splide {
    * @return `this`
    */
   add( slides: string | HTMLElement | Array<string | HTMLElement>, index?: number ): this {
-    this._C.Slides.add( slides, index );
+    this._Components.Slides.add( slides, index );
     return this;
   }
 
@@ -308,7 +308,7 @@ export class Splide {
    * @param matcher - An index, an array with indices, a selector string, or an iteratee function.
    */
   remove( matcher: SlideMatcher ): this {
-    this._C.Slides.remove( matcher );
+    this._Components.Slides.remove( matcher );
     return this;
   }
 
@@ -320,7 +320,7 @@ export class Splide {
    * @return `true` if the type matches the current one, or otherwise `false`.
    */
   is( type: string ): boolean {
-    return this._o.type === type;
+    return this._options.type === type;
   }
 
   /**
@@ -347,7 +347,7 @@ export class Splide {
       // Postpones destruction requested before the slider becomes ready.
       EventInterface( this ).on( EVENT_READY, this.destroy.bind( this, completely ) );
     } else {
-      forOwn( this._C, component => {
+      forOwn( this._Components, component => {
         component.destroy && component.destroy( completely );
       }, true );
 
@@ -366,7 +366,7 @@ export class Splide {
    * @return An object with the latest options.
    */
   get options(): Options {
-    return this._o;
+    return this._options;
   }
 
   /**
@@ -375,11 +375,11 @@ export class Splide {
    * @param options - An object with new options.
    */
   set options( options: Options ) {
-    const { _o } = this;
-    merge( _o, options );
+    const { _options } = this;
+    merge( _options, options );
 
     if ( ! this.state.is( CREATED ) ) {
-      this.emit( EVENT_UPDATED, _o );
+      this.emit( EVENT_UPDATED, _options );
     }
   }
 
@@ -389,7 +389,7 @@ export class Splide {
    * @return The number of slides.
    */
   get length(): number {
-    return this._C.Slides.getLength( true );
+    return this._Components.Slides.getLength( true );
   }
 
   /**
@@ -398,6 +398,6 @@ export class Splide {
    * @return The active slide index.
    */
   get index(): number {
-    return this._C.Controller.getIndex();
+    return this._Components.Controller.getIndex();
   }
 }

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio