// withHooks // noPage import esp from 'esoftplay/esp'; import { useEffect, useMemo, useRef } from 'react'; import { ScrollView, StyleProp, View, ViewStyle } from 'react-native'; export interface LibCarrousel_snapProps { data: any[] align?: 'center' | 'left' style?: StyleProp, maxWidth: number, autoCycle?: boolean, loop?: boolean, autoCycleDelay?: number, itemMarginHorizontal: number, itemWidth: number, onChangePage?: (page: number) => void, initialPage?: number, renderItem: (item: any, key: number | string, itemWidth: number) => any } /** Klik [disini](https://github.com/dev-esoftplay/mobile-docs/blob/main/modules/lib/carrousel_snap.md) untuk melihat dokumentasi*/ export default function m(props: LibCarrousel_snapProps): any { const LibFocus = useRef(esp.mod("lib/focus")).current const autoCycle = props.autoCycle || false const autoCycleDelay = props.autoCycleDelay || 4000 const align = props.align || 'center' const sRef = useRef(null) const itemWidth = props.itemWidth - (props.itemMarginHorizontal * 2) const adderLength = useMemo(() => prefix().length, [props.data]) const indexsData = useMemo(() => props.data.map((_, i) => i), [props.data]) const indexes = useMemo(() => [...prefixIndexs(), ...props.data.map((_, i) => i), ...suffixIndexs()], [props.data]) const views = useMemo(() => [...prefix(), ...props.data, ...suffix()], [props.data]) const renderOffsets = useMemo(() => views.map((_, i) => i * props.itemWidth), [props.data]) const wideMargin = (props.maxWidth - props.itemWidth) * 0.5 let thisPage = useRef(0).current let timmerTick: any = useRef().current useEffect(() => { let initialPage = props.initialPage || 0 if (props.loop) { initialPage += adderLength } thisPage = initialPage if (props.onChangePage) props.onChangePage(indexes[initialPage]) sRef.current?.scrollTo({ x: renderOffsets[initialPage], animated: false }) if (autoCycle && props.loop && props.align == 'center') timmer() return () => { if (timmerTick) { clearInterval(timmerTick) } } }, []) function renderItem(item: any, index: string | number): any { return ( {props.renderItem(item, index, itemWidth)} ) } function timmer() { timmerTick = setInterval(() => { toPage(thisPage + 1) }, autoCycleDelay); } function toPage(page: number) { let out = page if (align == 'left' && out == props.data.length - 1) { out = out - (props.maxWidth - props.itemWidth) } if (props.onChangePage) props.onChangePage(indexes[out]) if (props.loop) { if (out >= (props.data.length + adderLength)) { const a = indexes[out]; const b = indexsData.indexOf(a) + adderLength sRef.current?.scrollTo({ x: renderOffsets[out], animated: true }) thisPage = b return } } thisPage = out sRef.current?.scrollTo({ x: renderOffsets[out], animated: true }) } function onChangePage(e: any) { const offsetX = e.nativeEvent.contentOffset.x let out = 0 if (offsetX > 0) { out = (offsetX / props.itemWidth) if (align == 'left' && out == props.data.length) { out = out - (props.maxWidth - props.itemWidth) } } if (props.onChangePage) props.onChangePage(indexes[Math.round(out)]) if (props.loop) { let x = offsetX ? (offsetX / props.itemWidth) : 0 if (x <= adderLength || x >= (props.data.length + adderLength)) { const a = indexes[x]; const b = indexsData.indexOf(a) + adderLength sRef.current?.scrollTo({ x: renderOffsets[b], animated: false }) thisPage = b if (timmerTick) { clearInterval(timmerTick) timmer() return } } } thisPage = out if (timmerTick) { clearInterval(timmerTick) timmer() } } function prefixIndexs(): number[] { let out: any[] = [] const dataLength: number = (props.data.length || 0) if (props.loop) { if (dataLength == 1) { out.push(dataLength - 1) out.push(dataLength - 1) out.push(dataLength - 1) } else if (dataLength > 2) { out.push(dataLength - 3) out.push(dataLength - 2) out.push(dataLength - 1) } else { out.push(dataLength - 1) out.push(dataLength - 2) out.push(dataLength - 1) } } return out } function prefix(): any { let out: any[] = [] if (props.loop) { const dataLength = props.data.length if (dataLength == 1) { out.push(renderItem(props.data[dataLength - 1], 'x')) out.push(renderItem(props.data[dataLength - 1], 'y')) out.push(renderItem(props.data[dataLength - 1], 'z')) } else if (dataLength > 2) { out.push(renderItem(props.data[dataLength - 3], 'x')) out.push(renderItem(props.data[dataLength - 2], 'y')) out.push(renderItem(props.data[dataLength - 1], 'z')) } else { out.push(renderItem(props.data[dataLength - 1], 'x')) out.push(renderItem(props.data[dataLength - 2], 'y')) out.push(renderItem(props.data[dataLength - 1], 'z')) } } return out } function suffixIndexs(): number[] { let out: any[] = [] if (props.loop) { if (props.data.length == 1) { out.push(0) out.push(0) out.push(0) } else if (props.data.length > 2) { out.push(0) out.push(1) out.push(2) } else { out.push(0) out.push(1) out.push(0) } } return out } function suffix(): any { let out: any[] = [] if (props.loop) { if (props.data.length == 1) { out.push(renderItem(props.data[0], 'x')) out.push(renderItem(props.data[0], 'y')) out.push(renderItem(props.data[0], 'z')) } else if (props.data.length > 2) { out.push(renderItem(props.data[0], 'x')) out.push(renderItem(props.data[1], 'y')) out.push(renderItem(props.data[2], 'z')) } else { out.push(renderItem(props.data[0], 'x')) out.push(renderItem(props.data[1], 'y')) out.push(renderItem(props.data[0], 'z')) } } return out } return ( autoCycle && props.loop && props.align == 'center' ? timmer() : {}} onBlur={() => timmerTick ? clearInterval(timmerTick) : {}} /> {align == 'center' && } {prefix()} {props.data.map(renderItem)} {suffix()} {align == 'center' && } ) }