|
@@ -1,159 +1,4 @@
|
|
import React, {useRef, useEffect, useState} from 'react'
|
|
import React, {useRef, useEffect, useState} from 'react'
|
|
|
|
|
|
export default ({images = [], className, onChange, onClick, ...props}) => {
|
|
export default ({images = [], className, onChange, onClick, ...props}) => {
|
|
- const divRef = useRef()
|
|
|
|
- const containerRef = useRef()
|
|
|
|
- const autoscroll = useRef(false)
|
|
|
|
- const inTouch = useRef(false)
|
|
|
|
- const timeout = useRef(false)
|
|
|
|
-
|
|
|
|
- const [imgs, setImgs] = useState([])
|
|
|
|
- const [current, setCurrent] = useState(0)
|
|
|
|
- const currentScrollPosition = useRef(0)
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- useEffect(() => {
|
|
|
|
- if (divRef.current){
|
|
|
|
- const div = divRef.current
|
|
|
|
-
|
|
|
|
- const totalWidth = imgs.reduce((total, img) => total + (img?.getBoundingClientRect().width || 0),0)
|
|
|
|
- div.style.minWidth = totalWidth + 'px'
|
|
|
|
- }
|
|
|
|
- }, [divRef, imgs])
|
|
|
|
-
|
|
|
|
- const scrollToCurrent = () => {
|
|
|
|
- if (autoscroll.current || !containerRef.current) return;
|
|
|
|
-
|
|
|
|
- const el = containerRef.current
|
|
|
|
-
|
|
|
|
- const step = () => {
|
|
|
|
- if (!el) return;
|
|
|
|
-
|
|
|
|
- autoscroll.current = true
|
|
|
|
- const {scrollLeft} = el
|
|
|
|
- const diff = (currentScrollPosition.current - scrollLeft) /5
|
|
|
|
- if (Math.abs(diff) > 1){
|
|
|
|
- el.scrollTo(scrollLeft + diff, 0)
|
|
|
|
- setTimeout(step, 20)
|
|
|
|
- }
|
|
|
|
- else {
|
|
|
|
- el.scrollTo(currentScrollPosition.current, 0)
|
|
|
|
- autoscroll.current = false
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- step()
|
|
|
|
- //if (milaCount !== current +1) set(current +1)
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- const onTouchEnd = () => {
|
|
|
|
- if (inTouch.current){
|
|
|
|
- if (timeout.current) clearInterval(timeout.current)
|
|
|
|
-
|
|
|
|
- timeout.current = setTimeout(onTouchEnd, 200)
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- const {scrollLeft, scrollWidth} = containerRef.current;
|
|
|
|
- const viewPortWidth = containerRef.current.getBoundingClientRect().width
|
|
|
|
-
|
|
|
|
- let newCurrent;
|
|
|
|
- if (scrollLeft === 0) {
|
|
|
|
- newCurrent = 0
|
|
|
|
- currentScrollPosition.current = 0
|
|
|
|
- }
|
|
|
|
- else if (scrollLeft >= scrollWidth - viewPortWidth) {
|
|
|
|
- newCurrent = (images.length -1)
|
|
|
|
- currentScrollPosition.current = scrollWidth - viewPortWidth
|
|
|
|
- }
|
|
|
|
- else {
|
|
|
|
- let imgsWidth = 0
|
|
|
|
- let i = 0
|
|
|
|
- for (const img of imgs){
|
|
|
|
- const imgWidth = img?.getBoundingClientRect().width || 0
|
|
|
|
- imgsWidth += imgWidth
|
|
|
|
- if (imgsWidth > scrollLeft){
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- i++
|
|
|
|
- }
|
|
|
|
- const offset = imgsWidth - scrollLeft
|
|
|
|
- newCurrent = i
|
|
|
|
- currentScrollPosition.current = imgsWidth - (imgs?.[i].getBoundingClientRect().width || 0)
|
|
|
|
- if (offset < viewPortWidth/2){
|
|
|
|
- currentScrollPosition.current = imgsWidth
|
|
|
|
- newCurrent++
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- setCurrent(newCurrent)
|
|
|
|
- if (newCurrent === current) scrollToCurrent()
|
|
|
|
- else if (typeof onChange === 'function') onChange(newCurrent)
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- const onScroll = e => {
|
|
|
|
- if (autoscroll.current) return;
|
|
|
|
-
|
|
|
|
- if (timeout.current) clearInterval(timeout.current)
|
|
|
|
-
|
|
|
|
- timeout.current = setTimeout(onTouchEnd, 200)
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- useEffect(scrollToCurrent, [current])
|
|
|
|
-
|
|
|
|
- const isTouchDevice = () => (navigator.maxTouchPoints || 'ontouchstart' in document.documentElement);
|
|
|
|
-
|
|
|
|
- const onImgClick = (e, i) => {
|
|
|
|
- const touchDevice = isTouchDevice()
|
|
|
|
- if (touchDevice && typeof onClick === 'function'){
|
|
|
|
- onClick(i)
|
|
|
|
- }
|
|
|
|
- else {
|
|
|
|
- const viewPortWidth = containerRef.current.getBoundingClientRect().width
|
|
|
|
- const clickX = e.clientX -e.target.getBoundingClientRect().x
|
|
|
|
- const {scrollLeft} = containerRef.current;
|
|
|
|
- if (clickX > viewPortWidth * 0.75) {
|
|
|
|
- if (i < images.length -1){
|
|
|
|
- currentScrollPosition.current = scrollLeft + (imgs?.[i].getBoundingClientRect().width || 0)
|
|
|
|
- setCurrent(i +1)
|
|
|
|
- scrollToCurrent()
|
|
|
|
- if (typeof onChange === 'function') onChange(i +1)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- else if (clickX < viewPortWidth * 0.25) {
|
|
|
|
- if (i > 0){
|
|
|
|
- currentScrollPosition.current = scrollLeft - (imgs?.[i-1].getBoundingClientRect().width || 0)
|
|
|
|
- setCurrent(i -1)
|
|
|
|
- scrollToCurrent()
|
|
|
|
- if (typeof onChange === 'function') onChange(i -1)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- else if (typeof onClick === 'function'){
|
|
|
|
- onClick(i)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return (
|
|
|
|
- <div className={className}
|
|
|
|
- style={{cssText: `overflow: auto; -ms-overflow-style: none; scrollbar-width: none`}}
|
|
|
|
- onScroll={onScroll} //TODO: do it only on desktop, on touch devices use onTouchEnd
|
|
|
|
- ref={containerRef}
|
|
|
|
- {...isTouchDevice() ? {
|
|
|
|
- onTouchStart(){
|
|
|
|
- inTouch.current = true
|
|
|
|
- },
|
|
|
|
- onTouchEnd(){
|
|
|
|
- inTouch.current = false
|
|
|
|
- }
|
|
|
|
- }: {}}
|
|
|
|
- >
|
|
|
|
- <div ref={divRef}>
|
|
|
|
- {images.map((image, i) => <img src={image}
|
|
|
|
- key={`image_${i}`}
|
|
|
|
- alt={`image ${i}`}
|
|
|
|
- onLoad={e => {imgs[i] = e.target; setImgs([...imgs]) }}
|
|
|
|
- onClick={e => onImgClick(e, i)}
|
|
|
|
- />)}
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- )
|
|
|
|
}
|
|
}
|