UNPKG

@zohodesk/components

Version:

In this Package, we Provide Some Basic Components to Build Web App

195 lines (170 loc) • 6.33 kB
import React, { useContext, useEffect, useState, useRef, useMemo } from 'react'; import { CustomResponsiveSender_defaultProps, CustomResponsiveReceiver_defaultProps } from "./props/defaultProps"; import { CustomResponsiveSender_propTypes, CustomResponsiveReceiver_propTypes } from "./props/propTypes"; import ResizeObserver from "./ResizeObserver"; import DOMRefWrapper from "./RefWrapper"; import shallowCompare from "./utils/shallowCompare"; import { isBreackPointMatched, Subscribale, isTouchDevice, windowResizeObserver } from "./sizeObservers"; import { ContextOptimizer } from "../utils/ContextOptimizer"; // const commonBreakPoints = [ 480, 640, 768, 1024, 1440 ]; // const otherBreakPoints = [320, 360, 375, 720, 1280, 1600, 1920]; // defaultResponsiveId means if ResponsiveSender do not recive id This will be id const defaultResponsiveId = 'parent_sender'; // validSizeResponsiveId means in some parent's height and with is caluclated ( readed ) const validSizeResponsiveId = 'valid_sender'; const ResponsiveContext = /*#__PURE__*/React.createContext({ [validSizeResponsiveId]: windowResizeObserver }); export function ResponsiveSender(props) { // variables const { children, domRefKey, responsiveId } = props; function init() { let size = { height: 0, width: 0 }; function getSize() { return size; } const childContext = { resize: new Subscribale(), getSize, // TODO: rename isParentSize ==> isSizeReaded (or) isMySize (or) isOriginalSize isParentSize: false }; function onResize(newSize) { childContext.isParentSize = true; size = newSize; setTimeout(() => { childContext.resize.dispatch(newSize); }); } const observer = new ResizeObserver(onResize); function containerRef(node) { observer.replaceObservationElement(node); } return { containerRef, childContext }; } const { containerRef, childContext } = useMemo(init, []); function contextSelector(context) { const totalContext = { ...context }; totalContext[responsiveId] = childContext; // NOTE: this for fallback of if responsive receiver id wrong or not avelable Responcive id totalContext[defaultResponsiveId] = childContext; if (childContext.isParentSize) { totalContext[validSizeResponsiveId] = childContext; } return totalContext; } return /*#__PURE__*/React.createElement(ContextOptimizer, { Context: ResponsiveContext, calculation: contextSelector }, totalContext => /*#__PURE__*/React.createElement(ResponsiveContext.Provider, { value: totalContext }, /*#__PURE__*/React.createElement(DOMRefWrapper, { domRefKey: domRefKey, ref: containerRef }, children))); } ResponsiveSender.defaultProps = { ...CustomResponsiveSender_defaultProps, responsiveId: defaultResponsiveId }; ResponsiveSender.contextType = ResponsiveContext; ResponsiveSender.propTypes = CustomResponsiveSender_propTypes; export function useResponsiveReceiver() { let responsiveId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultResponsiveId; let query = arguments.length > 1 ? arguments[1] : undefined; const [, forceUpdate] = useState(); const totalContextData = useContext(ResponsiveContext); const validSizeContextData = totalContextData[validSizeResponsiveId]; const contextData = totalContextData[responsiveId] || totalContextData[defaultResponsiveId] || validSizeContextData; // NOTE: this for fallback of if responsive receiver id wrong const resizeHandlerRef = useRef(); const data = useRef(); function updateLatestData() { const size = contextData.isParentSize ? contextData.getSize() : validSizeContextData.getSize(); const prevData = data.current; data.current = query({ isTouchDevice, isParentSize: contextData.isParentSize, currentScreenSize: size, mediaQueryOR(breakPointArray) { return breakPointArray.some(breakPoint => { const { isHeight, isWidth } = isBreackPointMatched(breakPoint, size); return isHeight || isWidth; }); }, mediaQueryAND(breakPointArray) { return breakPointArray.every(breakPoint => { const { isHeight, isWidth } = isBreackPointMatched(breakPoint, size); return (isHeight === undefined ? true : isHeight) && (isWidth === undefined ? true : isWidth); }); } }); const isSameValues = shallowCompare(data.current, prevData); if (isSameValues) { data.current = prevData; } return isSameValues; } resizeHandlerRef.current = updateLatestData; useEffect(() => { function handleResize(size) { const isSameValues = resizeHandlerRef.current(size); !isSameValues && forceUpdate({}); } contextData.resize.subscribe(handleResize); return () => contextData.resize.unsubscribe(handleResize); }, [contextData]); // const prevContextDataRef = useRef(); // function handleResize(size) { // const prevData = data.current; // resizeHandlerRef.current(size); // const isSammeValues = shallowCompare(data.current, prevData); // !isSammeValues && forceUpdate({}); // } // if(prevContextDataRef.current !== contextData) { // prevContextDataRef.current = contextData; // contextData.resize.unsubscribe(handleResize); // windowResizeObserver.unobserve(handleResize); // if (contextData) { // contextData.resize.subscribe(handleResize); // } else { // windowResizeObserver.observe(handleResize); // } // } // NOTE: this call for we must give updated value updateLatestData(); return data.current; } export function ResponsiveReceiver(_ref) { let { children, responsiveId, query, eleRef, domRefKey } = _ref; const data = useResponsiveReceiver(responsiveId, query); const child = children(data); return eleRef ? /*#__PURE__*/React.createElement(DOMRefWrapper, { domRefKey: domRefKey, ref: eleRef }, child) : child; } ResponsiveReceiver.defaultProps = { ...CustomResponsiveReceiver_defaultProps, responsiveId: defaultResponsiveId }; ResponsiveReceiver.propTypes = CustomResponsiveReceiver_propTypes;