@zohodesk/components
Version:
In this Package, we Provide Some Basic Components to Build Web App
195 lines (170 loc) • 6.33 kB
JavaScript
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;