Skip to content
This repository has been archived by the owner on Jun 1, 2024. It is now read-only.

Feat/list view pagination #122

Merged
merged 9 commits into from
Aug 13, 2020
2 changes: 1 addition & 1 deletion src/components/BeagleContainer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const BeagleContainer: FC<BeagleContainerInterface> = props => {
}, [])

return (
<StyledContainer className={className} style={style}>
<StyledContainer className={`${className} container`} style={style}>
{children}
</StyledContainer>
)
Expand Down
106 changes: 102 additions & 4 deletions src/components/BeagleFutureListView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,89 @@
* limitations under the License.
*/

import React, { FC, useEffect } from 'react'
import React, { FC, useEffect, useRef, useState } from 'react'
import { BeagleUIElement } from '@zup-it/beagle-web'
import Expression from '@zup-it/beagle-web/beagle-view/render/expression'
import { Tree } from '@zup-it/beagle-web'
import { BeagleComponent } from '../../types'
import { Direction, BeagleDefaultComponent } from '../types'
import withTheme from '../utils/withTheme'
import { StyledListView } from './styled'


export type NodeType = HTMLElement | null

export interface BeagleListViewInterface extends BeagleDefaultComponent, BeagleComponent {
direction: Direction,
dataSource: any[],
onInit?: () => void,
onScrollEnd?: () => void,
scrollEndThreshold?: number,
template: BeagleUIElement,
useParentScroll?: boolean,
}

const BeagleListView: FC<BeagleListViewInterface> = ({
direction,
direction = 'VERTICAL',
className,
style,
template,
onInit,
onScrollEnd,
scrollEndThreshold = 100,
dataSource,
beagleContext,
children,
useParentScroll = false,
}) => {
const allowedOnScrollRef = useRef(true)
const elementRef = useRef() as React.MutableRefObject<HTMLDivElement>
let node: NodeType

const hasHorizontalScroll = (nodeElement: NodeType): boolean => {
if (!nodeElement) return false

const overflowX = getComputedStyle(nodeElement).overflowX

const hasXScroll = overflowX !== 'visible' && overflowX !== 'hidden'

return (nodeElement.clientWidth === 0 ||
nodeElement.scrollWidth <= nodeElement.clientWidth ||
!hasXScroll)
}

const hasVerticalScroll = (nodeElement: NodeType): boolean => {
if (!nodeElement) return false

const overflowY = getComputedStyle(nodeElement).overflowY
const hasYScroll = overflowY !== 'visible' && overflowY !== 'hidden'
return (nodeElement.clientHeight === 0 ||
nodeElement.scrollHeight <= nodeElement.clientHeight ||
!hasYScroll)
}

const getParentNode = (nodeElement: NodeType): NodeType => {
if (!nodeElement) return null
if (nodeElement.nodeName === 'HTML') return nodeElement

if (direction === 'VERTICAL' && hasVerticalScroll(nodeElement) ||
direction === 'HORIZONTAL' && hasHorizontalScroll(nodeElement))
return getParentNode(nodeElement.parentNode as HTMLElement)

return nodeElement
}

const getReferenceNode = (): NodeType => {
if (!elementRef || !elementRef.current)
return null

if (useParentScroll) {
let parentNode = elementRef.current.parentNode as NodeType
parentNode = getParentNode(parentNode)
return parentNode as NodeType
}
return (elementRef.current as NodeType)
}

useEffect(() => {
if (onInit) onInit()
}, [])
Expand All @@ -57,10 +114,51 @@ const BeagleListView: FC<BeagleListViewInterface> = ({
})

beagleContext.getView().getRenderer().doFullRender(element, element.id)
allowedOnScrollRef.current = true

}, [JSON.stringify(dataSource)])

const callOnScrollEnd = () => onScrollEnd && onScrollEnd()

const calcPercentage = () => {
if (!node) return

let screenPercentage: number
if (direction === 'VERTICAL') {
const scrollPosition = node.scrollTop
screenPercentage = (scrollPosition /
(node.scrollHeight - node.clientHeight)) * 100
} else {
const scrollPosition = node.scrollLeft
screenPercentage = (scrollPosition /
(node.scrollWidth - node.clientWidth)) * 100
}

if (scrollEndThreshold && Math.ceil(screenPercentage) >= scrollEndThreshold
&& allowedOnScrollRef.current) {
allowedOnScrollRef.current = false
callOnScrollEnd()
}
}

useEffect(() => {
const referenceNode = getReferenceNode()
if (referenceNode !== node) {
if (node !== undefined && node !== null) node.removeEventListener('scroll', calcPercentage)
node = referenceNode

const parent = (node && node.nodeName !== 'HTML')
? node : window

parent.addEventListener('scroll', calcPercentage)
return () => parent.removeEventListener('scroll', calcPercentage)
}
}, [children])

return (
<StyledListView className={className} direction={direction} style={style}>
<StyledListView ref={elementRef}
className={className} direction={direction}
useParentScroll={useParentScroll} style={style}>
{children}
</StyledListView>
)
Expand Down
8 changes: 7 additions & 1 deletion src/components/BeagleFutureListView/styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,15 @@ import { Direction } from '../types'

interface StyledListViewInterface {
direction: Direction,
useParentScroll?: boolean,
}

export const StyledListView = styled.div<StyledListViewInterface>`
display: flex;
flex-direction: ${({ direction }) => direction === 'VERTICAL' ? 'column' : 'row'}
flex-direction: ${({ direction }) => direction === 'VERTICAL' ? 'column' : 'row'};
overflow: ${({ useParentScroll }) => useParentScroll ? '' : 'auto'};

.container {
overflow: visible;
}
`