Sync.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. import { ARIA_ORIENTATION } from '../../constants/attributes';
  2. import { TTB } from '../../constants/directions';
  3. import {
  4. EVENT_CLICK,
  5. EVENT_MOUNTED,
  6. EVENT_MOVE,
  7. EVENT_NAVIGATION_MOUNTED,
  8. EVENT_SLIDE_KEYDOWN,
  9. EVENT_UPDATED,
  10. } from '../../constants/events';
  11. import { LOOP } from '../../constants/types';
  12. import { EventInterface, EventInterfaceObject } from '../../constructors';
  13. import { Splide } from '../../core/Splide/Splide';
  14. import { BaseComponent, Components, Options } from '../../types';
  15. import { apply, empty, includes, isUndefined, prevent, setAttribute } from '../../utils';
  16. import { normalizeKey } from '../../utils/dom/normalizeKey/normalizeKey';
  17. import { SlideComponent } from '../Slides/Slide';
  18. /**
  19. * The interface for the Sync component.
  20. *
  21. * @since 3.0.0
  22. */
  23. export interface SyncComponent extends BaseComponent {
  24. remount(): void;
  25. }
  26. /**
  27. * The keys for triggering the navigation slide.
  28. *
  29. * @since 3.0.0
  30. */
  31. const TRIGGER_KEYS = [ ' ', 'Enter' ];
  32. /**
  33. * The component for syncing multiple sliders.
  34. *
  35. * @since 3.0.0
  36. *
  37. * @param Splide - A Splide instance.
  38. * @param Components - A collection of components.
  39. * @param options - Options.
  40. *
  41. * @return A Sync component object.
  42. */
  43. export function Sync( Splide: Splide, Components: Components, options: Options ): SyncComponent {
  44. const { isNavigation, slideFocus } = options;
  45. /**
  46. * Stores event objects.
  47. */
  48. const events: EventInterfaceObject[] = [];
  49. /**
  50. * Called when the component is mounted.
  51. */
  52. function mount(): void {
  53. Splide.splides.forEach( target => {
  54. if ( ! target.isParent ) {
  55. sync( Splide, target.splide );
  56. sync( target.splide, Splide );
  57. }
  58. } );
  59. if ( isNavigation ) {
  60. navigate();
  61. }
  62. }
  63. /**
  64. * Destroys the component.
  65. */
  66. function destroy(): void {
  67. events.forEach( event => { event.destroy() } );
  68. empty( events );
  69. }
  70. /**
  71. * Remounts the component.
  72. *
  73. * @internal
  74. */
  75. function remount(): void {
  76. destroy();
  77. mount();
  78. }
  79. /**
  80. * Syncs the current index with a provided child splide instance.
  81. *
  82. * @param splide - A splide instance to sync with.
  83. * @param target - A target splide instance.
  84. */
  85. function sync( splide: Splide, target: Splide ): void {
  86. const event = EventInterface( splide );
  87. event.on( EVENT_MOVE, ( index, prev, dest ) => {
  88. target.go( target.is( LOOP ) ? dest : index );
  89. } );
  90. events.push( event );
  91. }
  92. /**
  93. * Makes slides clickable and moves the slider to the index of clicked slide.
  94. * Note that the direction of `menu` is implicitly `vertical` as default.
  95. */
  96. function navigate(): void {
  97. const event = EventInterface( Splide );
  98. const { on } = event;
  99. on( EVENT_CLICK, onClick );
  100. on( EVENT_SLIDE_KEYDOWN, onKeydown );
  101. on( [ EVENT_MOUNTED, EVENT_UPDATED ], update );
  102. events.push( event );
  103. event.emit( EVENT_NAVIGATION_MOUNTED, Splide.splides );
  104. }
  105. /**
  106. * Update attributes.
  107. */
  108. function update(): void {
  109. setAttribute( Components.Elements.list, ARIA_ORIENTATION, options.direction === TTB ? 'vertical' : '' );
  110. }
  111. /**
  112. * Called when the navigation slide is clicked.
  113. *
  114. * @param Slide - A clicked Slide component.
  115. */
  116. function onClick( Slide: SlideComponent ): void {
  117. Splide.go( Slide.index );
  118. }
  119. /**
  120. * Called when any key is pressed on the navigation slide.
  121. *
  122. * @param Slide - A Slide component.
  123. * @param e - A KeyboardEvent object.
  124. */
  125. function onKeydown( Slide: SlideComponent, e: KeyboardEvent ): void {
  126. if ( includes( TRIGGER_KEYS, normalizeKey( e ) ) ) {
  127. onClick( Slide );
  128. prevent( e );
  129. }
  130. }
  131. return {
  132. setup: apply(
  133. Components.Media.set,
  134. { slideFocus: isUndefined( slideFocus ) ? isNavigation : slideFocus },
  135. true
  136. ),
  137. mount,
  138. destroy,
  139. remount,
  140. };
  141. }