123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- import { SlideComponent } from '@splidejs/splide';
- import {
- ALL_ATTRIBUTES,
- ARIA_CONTROLS,
- ARIA_CURRENT,
- ARIA_HIDDEN,
- ARIA_LABEL,
- ROLE,
- TAB_INDEX,
- } from '../../constants/attributes';
- import {
- CLASS_ACTIVE,
- CLASS_CONTAINER,
- CLASS_NEXT,
- CLASS_PREV,
- CLASS_VISIBLE,
- STATUS_CLASSES,
- } from '../../constants/classes';
- import {
- EVENT_ACTIVE,
- EVENT_CLICK,
- EVENT_HIDDEN,
- EVENT_INACTIVE,
- EVENT_MOUNTED,
- EVENT_MOVE,
- EVENT_MOVED,
- EVENT_RESIZED, EVENT_SCROLLED,
- EVENT_SLIDE_KEYDOWN,
- EVENT_UPDATED,
- EVENT_VISIBLE,
- } from '../../constants/events';
- import { FADE, SLIDE } from '../../constants/types';
- import { Splide } from '../../core/Splide/Splide';
- import { EventInterface } from '../../constructors';
- import {
- abs,
- ceil,
- child,
- floor,
- hasClass,
- isHTMLButtonElement,
- min,
- rect,
- removeAttribute,
- removeClass,
- setAttribute,
- toggleClass,
- } from '../../utils';
- import { format, pad } from '../../utils/string';
- /**
- * The sub component for managing each slide.
- *
- * @since 3.0.0
- *
- * @param Splide - A Splide instance.
- * @param index - A slide index.
- * @param slideIndex - A slide index for clones. This must be `-1` if the slide is not clone.
- * @param slide - A slide element.
- *
- * @return A Slide sub component.
- */
- export function Slide( Splide: Splide, index: number, slideIndex: number, slide: HTMLElement ): SlideComponent {
- const { on, emit, bind, destroy: destroyEvents } = EventInterface( Splide );
- const { Components, root, options } = Splide;
- const { isNavigation, updateOnMove } = options;
- const { resolve } = Components.Direction;
- const isClone = slideIndex > -1;
- const container = child( slide, `.${ CLASS_CONTAINER }` );
- /**
- * Called when the component is mounted.
- */
- function mount( this: SlideComponent ): void {
- init();
- bind( slide, 'click keydown', e => {
- emit( e.type === 'click' ? EVENT_CLICK : EVENT_SLIDE_KEYDOWN, this, e );
- } );
- on( [ EVENT_MOUNTED, EVENT_MOVED, EVENT_UPDATED, EVENT_RESIZED, EVENT_SCROLLED ], update.bind( this ) );
- if ( updateOnMove ) {
- on( EVENT_MOVE, onMove );
- }
- }
- /**
- * If the `updateOnMove` option is `true`, called when the slider starts moving.
- *
- * @param next - A next index.
- * @param prev - A previous index.
- * @param dest - A destination index.
- */
- function onMove( next: number, prev: number, dest: number ): void {
- if ( dest === index ) {
- updateActivity.call( this, true );
- }
- update.call( this );
- }
- /**
- * Initializes the component.
- */
- function init(): void {
- if ( ! isClone ) {
- slide.id = `${ root.id }-slide${ pad( index + 1 ) }`;
- }
- if ( isNavigation ) {
- if ( ! isHTMLButtonElement( slide ) ) {
- setAttribute( slide, ROLE, 'button' );
- }
- const idx = isClone ? slideIndex : index;
- const label = format( options.i18n.slideX, idx + 1 );
- const controls = Splide.splides.map( splide => splide.root.id ).join( ' ' );
- setAttribute( slide, ARIA_LABEL, label );
- setAttribute( slide, ARIA_CONTROLS, controls );
- }
- }
- /**
- * Destroys the component.
- */
- function destroy(): void {
- destroyEvents();
- removeClass( slide, STATUS_CLASSES );
- removeAttribute( slide, ALL_ATTRIBUTES );
- }
- /**
- * Updates attribute and classes of the slide.
- */
- function update( this: SlideComponent ): void {
- if ( Components.Controller ) {
- const { index: currIndex } = Splide;
- updateActivity.call( this, isActive() );
- updateVisibility.call( this, isVisible() );
- toggleClass( slide, CLASS_PREV, index === currIndex - 1 );
- toggleClass( slide, CLASS_NEXT, index === currIndex + 1 );
- }
- }
- /**
- * Updates the status related with activity.
- *
- * @param active - Set `true` if the slide is active.
- */
- function updateActivity( this: SlideComponent, active: boolean ): void {
- toggleClass( slide, CLASS_ACTIVE, active );
- if ( active ) {
- if ( ! hasClass( slide, CLASS_ACTIVE ) ) {
- isNavigation && setAttribute( slide, ARIA_CURRENT, true );
- emit( EVENT_ACTIVE, this );
- }
- } else {
- if ( hasClass( slide, CLASS_ACTIVE ) ) {
- removeAttribute( slide, ARIA_CURRENT );
- emit( EVENT_INACTIVE, this );
- }
- }
- }
- /**
- * Updates the status related with visibility.
- *
- * @param visible - Set `true` if the slide is visible.
- */
- function updateVisibility( this: SlideComponent, visible: boolean ): void {
- toggleClass( slide, CLASS_VISIBLE, visible );
- setAttribute( slide, ARIA_HIDDEN, ! visible || null );
- setAttribute( slide, TAB_INDEX, visible && options.slideFocus ? 0 : null );
- if ( visible ) {
- if ( ! hasClass( slide, CLASS_VISIBLE ) ) {
- emit( EVENT_VISIBLE, this );
- }
- } else {
- if ( hasClass( slide, CLASS_VISIBLE ) ) {
- emit( EVENT_HIDDEN, this );
- }
- }
- }
- /**
- * Adds a CSS rule to the slider or the container.
- *
- * @param prop - A property name.
- * @param value - A CSS value to add.
- * @param useContainer - Optional. Determines whether to apply the rule to the container or not.
- */
- function rule( prop: string, value: string | number, useContainer?: boolean ): void {
- const selector = `#${ slide.id }${ container && useContainer ? ` > .${ CLASS_CONTAINER }` : '' }`;
- Components.Style.rule( selector, prop, value );
- }
- /**
- * Checks if the slide is active or not.
- *
- * @return `true` if the slide is active.
- */
- function isActive(): boolean {
- return Splide.index === index;
- }
- /**
- * Checks if the slide is visible or not.
- */
- function isVisible(): boolean {
- if ( Splide.is( FADE ) ) {
- return isActive();
- }
- const trackRect = rect( Components.Elements.track );
- const slideRect = rect( slide );
- const left = resolve( 'left' );
- const right = resolve( 'right' );
- return floor( trackRect[ left ] ) <= slideRect[ left ] && slideRect[ right ] <= ceil( trackRect[ right ] );
- }
- /**
- * Calculates how far this slide is from another slide and
- * returns `true` if the distance is within the given number.
- *
- * @param from - An index of a base slide.
- * @param distance - `true` if the slide is within this number.
- *
- * @return `true` if the slide is within the `distance` from the base slide, or otherwise `false`.
- */
- function isWithin( from: number, distance: number ): boolean {
- let diff = abs( from - index );
- if ( ! Splide.is( SLIDE ) && ! isClone ) {
- diff = min( diff, Splide.length - diff );
- }
- return diff <= distance;
- }
- return {
- index,
- slideIndex,
- slide,
- container,
- isClone,
- mount,
- destroy,
- rule,
- isWithin,
- };
- }
|