diff --git a/src/components/variant/drawer.utils.ts b/src/components/variant/drawer.utils.ts index a0d64b568..a55480930 100644 --- a/src/components/variant/drawer.utils.ts +++ b/src/components/variant/drawer.utils.ts @@ -1,4 +1,4 @@ -import { useState } from 'react' +import { useEffect, useState } from 'react' export enum DrawerClass { normClass = 'norm', @@ -63,5 +63,15 @@ export const useScrollShadow = ( } } + useEffect(() => { + if (element) { + console.log(element.childNodes[0].childNodes[0]) + /*const topShadow = createShadow(element, 'top') + const rightShadow = createShadow(element, 'right') + const bottomShadow = createShadow(element, 'bottom') + const leftShadow = createShadow(element, 'left')*/ + } + }, [element]) + return { shouldAddShadow, handleScroll, handleStartScroll } } diff --git a/src/ui/scroll-shadower/scroll-shadowier.tsx b/src/ui/scroll-shadower/scroll-shadowier.tsx index 71c0414e1..9a719ce64 100644 --- a/src/ui/scroll-shadower/scroll-shadowier.tsx +++ b/src/ui/scroll-shadower/scroll-shadowier.tsx @@ -1,125 +1,139 @@ import React, { FC, useEffect, useRef } from 'react' +import cn, { Argument } from 'classnames' import { - Container, - RootContainer, - ShadowBottom, - ShadowLeft, - ShadowRight, - ShadowTop, -} from '@ui/scroll-shadower/scroll-shadowier.styles' + createShadow, + createTrigger, + DisplayValue, + Placement, +} from '@ui/scroll-shadower/scroll-shadowier.utils' + +interface Prop { + classname: Argument +} -export const ScrollShadowier: FC = ({ children, ...props }) => { - const ref = useRef(null) - const left = useRef(null) - const right = useRef(null) - const bottom = useRef(null) - const top = useRef(null) +export const ScrollShadowier: FC = ({ classname, children }) => { + const shadowsRef = useRef(null) + const scrollableRef = useRef(null) useEffect(() => { - const resizeHandler = () => { - if ( - !ref.current || - !top.current || - !bottom.current || - !left.current || - !right.current - ) { - return - } - - const { - offsetWidth = 0, - offsetHeight = 0, - clientHeight = 0, - clientWidth = 0, - } = ref.current || {} - - const verticalOffset = offsetHeight - clientHeight - const horizontalOffset = offsetWidth - clientWidth - - bottom.current.style.bottom = verticalOffset + 'px' - bottom.current.style.right = horizontalOffset + 'px' - - top.current.style.right = horizontalOffset + 'px' + const scrollable = scrollableRef.current + const shadows = shadowsRef.current + if (!scrollable || !shadows) { + return + } - right.current.style.right = horizontalOffset + 'px' - right.current.style.bottom = verticalOffset + 'px' + const area = scrollable?.firstElementChild as HTMLDivElement - left.current.style.bottom = verticalOffset + 'px' + if (!area) { + return } - const scrollHandler = () => { - if ( - !ref.current || - !top.current || - !bottom.current || - !left.current || - !right.current - ) { - return - } + const topTrigger = createTrigger(area, Placement.top) + const rightTrigger = createTrigger(area, Placement.right) + const bottomTrigger = createTrigger(area, Placement.bottom) + const leftTrigger = createTrigger(area, Placement.left) - const none = 'none' - const initial = 'initial' + const topShadow = createShadow(shadows, Placement.top) + const rightShadow = createShadow(shadows, Placement.right) + const bottomShadow = createShadow(shadows, Placement.bottom) + const leftShadow = createShadow(shadows, Placement.left) + const resizeObserver = new ResizeObserver(entries => { const { - scrollWidth = 0, - scrollLeft = 0, - offsetWidth = 0, - scrollHeight = 0, - scrollTop = 0, - offsetHeight = 0, - clientHeight = 0, - clientWidth = 0, - } = ref.current || {} - - const verticalOffset = offsetHeight - clientHeight - const horizontalOffset = offsetWidth - clientWidth - - const onLeft = scrollLeft != 0 - const onRight = scrollLeft + offsetWidth + horizontalOffset < scrollWidth - const onTop = scrollTop > 0 - const onBottom = scrollTop + offsetHeight + verticalOffset < scrollHeight - - left.current.style.display = onLeft ? initial : none - right.current.style.display = onRight ? initial : none - top.current.style.display = onTop ? initial : none - bottom.current.style.display = onBottom ? initial : none - } - /* const options = { - root: ref.current, - rootMargin: '0px', - threshold: [0.0, 1.0], - }*/ - const resizeObserver = new ResizeObserver(resizeHandler) - //const scrollObserver = new IntersectionObserver(scrollHandler, options) - - scrollHandler() - resizeHandler() - - const node = ref.current - if (!node) return + contentRect: { width, height }, + } = entries[0] + shadows.style.width = `${width}px` + shadows.style.height = `${height}px` + }) + + resizeObserver.observe(scrollable) + + const intersectionObserver = new IntersectionObserver( + entries => { + for (const entry of entries) { + switch (entry.target) { + case topTrigger: + topShadow.style.display = entry.isIntersecting + ? DisplayValue.none + : DisplayValue.block + break + case rightTrigger: + rightShadow.style.display = entry.isIntersecting + ? DisplayValue.none + : DisplayValue.block + break + case bottomTrigger: + bottomShadow.style.display = entry.isIntersecting + ? DisplayValue.none + : DisplayValue.block + break + case leftTrigger: + leftShadow.style.display = entry.isIntersecting + ? DisplayValue.none + : DisplayValue.block + break + } + } + }, + { + root: scrollable, + }, + ) + intersectionObserver.observe(topTrigger) + intersectionObserver.observe(rightTrigger) + intersectionObserver.observe(bottomTrigger) + intersectionObserver.observe(leftTrigger) - //scrollObserver.observe(ref.current) - node.addEventListener('scroll', scrollHandler) - resizeObserver.observe(node) return () => { - resizeObserver.unobserve(node) - node.removeEventListener('scroll', scrollHandler) - //scrollObserver.unobserve(ref.current) + ;[ + topTrigger, + rightTrigger, + bottomTrigger, + leftTrigger, + topShadow, + rightShadow, + bottomShadow, + leftShadow, + ].forEach(target => target.remove()) + intersectionObserver.disconnect() + resizeObserver.disconnect() } }, []) return ( - - - - - - - {children} - - +
+
+
+
+ {children} +
+
+
) } diff --git a/src/ui/scroll-shadower/scroll-shadowier.utils.ts b/src/ui/scroll-shadower/scroll-shadowier.utils.ts new file mode 100644 index 000000000..fea178cd2 --- /dev/null +++ b/src/ui/scroll-shadower/scroll-shadowier.utils.ts @@ -0,0 +1,70 @@ +export enum Placement { + top = 'top', + bottom = 'bottom', + left = 'left', + right = 'right', +} + +export enum DisplayValue { + initial = 'initial', + none = 'none', + block = 'block', +} + +export const getBackground = (placement: Placement) => { + return `linear-gradient(to ${placement}, rgba(255, 255, 255, 0), rgba(0, 0, 0, 0.25))` +} + +export const createShadow = ( + container: HTMLDivElement, + placement: Placement, +) => { + const size = '20px' + const shadow = document.createElement('div') + + Object.assign(shadow.style, { + position: 'absolute', + display: DisplayValue.initial, + zIndex: 2, + top: placement === Placement.bottom ? undefined : 0, + right: placement === Placement.left ? undefined : 0, + bottom: placement === Placement.top ? undefined : 0, + left: placement === Placement.right ? undefined : 0, + width: + placement === Placement.left || placement === Placement.right + ? size + : undefined, + height: + placement === Placement.top || placement === Placement.bottom + ? size + : undefined, + background: getBackground(placement), + }) + + container.appendChild(shadow) + + return shadow +} + +export const createTrigger = ( + container: HTMLDivElement, + placement: Placement, +): HTMLElement => { + const trigger = document.createElement('div') + + Object.assign(trigger.style, { + position: 'absolute', + zIndex: 10, + left: placement === Placement.right ? '100%' : 0, + right: placement === Placement.left ? '100%' : 0, + top: placement === Placement.bottom ? '100%' : 0, + bottom: placement === Placement.top ? '100%' : 0, + }) + + trigger.style.position = 'absolute' + trigger.style.zIndex + + container.appendChild(trigger) + + return trigger +}