SelectionList.jsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // styling
  2. import styled from 'styled-components/macro';
  3. import {css} from 'styled-components';
  4. import theme from 'styled-theming';
  5. // components
  6. import SelectionButton from '@ui/SelectionButton';
  7. import {Swiper, SwiperSlide} from 'swiper/react';
  8. // hooks
  9. import {useEffect, useState} from 'react';
  10. import {useThemeProvider} from '@contexts/themeContext';
  11. // utils
  12. import PropTypes from 'prop-types';
  13. const prevButton = css`
  14. padding-left: 10px;
  15. background: ${theme('theme', {
  16. light: 'linear-gradient(90deg, #FFFFFF 28.49%, rgba(255, 255, 255, 0.0001) 100%);',
  17. dark: 'linear-gradient(-90deg, rgba(17, 19, 18, 0.0001) 0%, #111312 77.09%);'
  18. })};
  19. border-radius: 4px 0 0 0;
  20. `;
  21. const nextButton = css`
  22. padding-right: 10px;
  23. background: ${theme('theme', {
  24. light: 'linear-gradient(-90deg, #FFFFFF 28.49%, rgba(255, 255, 255, 0.0001) 100%);',
  25. dark: 'linear-gradient(90deg, rgba(17, 19, 18, 0.0001) 0%, #111312 77.09%);'
  26. })};
  27. border-radius: 0 4px 0 0;
  28. `;
  29. const StyledSelectionList = styled.div`
  30. display: flex;
  31. gap: 20px;
  32. box-shadow: 0 1px 8px rgba(110, 110, 110, 0.1);
  33. background: ${theme('theme', {
  34. light: 'var(--widget)',
  35. dark: '#1B1F23'
  36. })};
  37. position: relative;
  38. .swiper {
  39. padding: 20px 0;
  40. }
  41. .swiper-slide {
  42. width: fit-content;
  43. }
  44. .nav {
  45. display: flex;
  46. align-items: center;
  47. justify-content: space-between;
  48. position: absolute;
  49. top: 0;
  50. left: 0;
  51. width: 100%;
  52. height: 100%;
  53. z-index: 10;
  54. button {
  55. width: 50px;
  56. height: 100%;
  57. display: flex;
  58. align-items: center;
  59. color: #8EA2AB;
  60. }
  61. &.ltr button {
  62. &:first-child {
  63. ${prevButton};
  64. justify-content: flex-start;
  65. }
  66. &:last-child {
  67. ${nextButton};
  68. justify-content: flex-end;
  69. }
  70. }
  71. &.rtl button {
  72. &:first-child {
  73. ${nextButton};
  74. justify-content: flex-start;
  75. }
  76. &:last-child {
  77. ${prevButton};
  78. justify-content: flex-end;
  79. }
  80. }
  81. }
  82. `;
  83. const SelectionList = ({active, setActive, options, innerRef}) => {
  84. const [swiper, setSwiper] = useState(null);
  85. const {direction} = useThemeProvider();
  86. const handlePrev = () => {
  87. swiper.slidePrev();
  88. setActive(options[swiper.realIndex].value || options[swiper.realIndex]);
  89. }
  90. const handleNext = () => {
  91. swiper.slideNext();
  92. setActive(options[swiper.realIndex].value || options[swiper.realIndex]);
  93. }
  94. useEffect(() => {
  95. if (swiper) {
  96. swiper.changeLanguageDirection(direction);
  97. swiper.update();
  98. }
  99. }, [swiper, direction]);
  100. return (
  101. <StyledSelectionList ref={innerRef}>
  102. <div className={`nav ${direction}`}>
  103. <button aria-label="Previous" onClick={handlePrev}>
  104. <i className="icon icon-chevron-left"/>
  105. </button>
  106. <button aria-label="Next" onClick={handleNext}>
  107. <i className="icon icon-chevron-right"/>
  108. </button>
  109. </div>
  110. <Swiper className="selection-list w-100 h-100"
  111. onSwiper={setSwiper}
  112. slidesPerView="auto"
  113. spaceBetween={12}
  114. loop={true}
  115. centeredSlides={true}>
  116. {
  117. options.map(option => (
  118. <SwiperSlide key={option.label || option}>
  119. <SelectionButton text={option.label || option}
  120. active={active === option.value || active === option}
  121. onClick={() => setActive(option.value || option)}/>
  122. </SwiperSlide>
  123. ))
  124. }
  125. </Swiper>
  126. </StyledSelectionList>
  127. )
  128. }
  129. SelectionList.propTypes = {
  130. active: PropTypes.string,
  131. setActive: PropTypes.func,
  132. options: PropTypes.array,
  133. innerRef: PropTypes.any
  134. }
  135. export default SelectionList