Options.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import { DESTROYED } from '../../constants/states';
  2. import { EventInterface } from '../../constructors';
  3. import { Splide } from '../../core/Splide/Splide';
  4. import { BaseComponent, Components, Options } from '../../types';
  5. import { find, isUndefined, merge, noop } from '../../utils';
  6. /**
  7. * The interface for the Options component.
  8. *
  9. * @since 3.0.0
  10. */
  11. export interface OptionsComponent extends BaseComponent {
  12. fix<K extends keyof Options>( key: K, value?: Options[ K ] ): void;
  13. }
  14. /**
  15. * The component for managing options.
  16. *
  17. * @since 3.0.0
  18. *
  19. * @param Splide - A Splide instance.
  20. * @param Components - A collection of components.
  21. * @param options - Options.
  22. *
  23. * @return An Options component object.
  24. */
  25. export function Options( Splide: Splide, Components: Components, options: Options ): OptionsComponent {
  26. const event = EventInterface( Splide, true );
  27. const breakpoints = options.breakpoints || {};
  28. /**
  29. * Keeps the initial options to apply when no matched query exists.
  30. */
  31. const userOptions: Options = merge( {}, options );
  32. /**
  33. * Stores fixed options.
  34. */
  35. const fixedOptions: Options = {};
  36. /**
  37. * Stores breakpoints with the MediaQueryList object.
  38. */
  39. let points: [ string, MediaQueryList ][];
  40. /**
  41. * Called when the component is constructed.
  42. */
  43. function setup(): void {
  44. const isMin = options.mediaQuery === 'min';
  45. points = Object.keys( breakpoints )
  46. .sort( ( n, m ) => isMin ? +m - +n : +n - +m )
  47. .map( point => {
  48. const queryList = matchMedia( `(${ isMin ? 'min' : 'max' }-width:${ point }px)` );
  49. event.bind( queryList, 'change', check );
  50. return [ point, queryList ];
  51. } );
  52. check();
  53. }
  54. /**
  55. * Destroys the component.
  56. *
  57. * @param completely - Will be `true` for complete destruction.
  58. */
  59. function destroy( completely: boolean ): void {
  60. if ( completely ) {
  61. event.destroy();
  62. }
  63. }
  64. /**
  65. * Observes breakpoints.
  66. */
  67. function check(): void {
  68. const point = ( find( points, item => item[ 1 ].matches ) || [] )[ 0 ];
  69. const newOptions = merge( {}, breakpoints[ point ] || userOptions, fixedOptions );
  70. if ( newOptions.destroy ) {
  71. Splide.options = userOptions;
  72. Splide.destroy( newOptions.destroy === 'completely' );
  73. } else {
  74. if ( Splide.state.is( DESTROYED ) ) {
  75. destroy( true );
  76. Splide.mount();
  77. } else {
  78. Splide.options = newOptions;
  79. }
  80. }
  81. }
  82. /**
  83. * Fixes options to prevent breakpoints from overwriting them.
  84. *
  85. * @param key - A key.
  86. * @param value - Optional. A value to fix. If omitted, the value will be restored.
  87. */
  88. function fix<K extends keyof Options>( key: K, value?: Options[ K ] ): void {
  89. if ( fixedOptions[ key ] !== value ) {
  90. if ( isUndefined( value ) ) {
  91. delete fixedOptions[ key ];
  92. } else {
  93. fixedOptions[ key ] = value;
  94. }
  95. check();
  96. }
  97. }
  98. return {
  99. setup,
  100. mount: noop,
  101. destroy,
  102. fix,
  103. };
  104. }