@zohodesk/components
Version:
In this Package, we Provide Some Basic Components to Build Web App
194 lines (164 loc) • 6.11 kB
JavaScript
import React, { useContext, useEffect, useState, useMemo } from 'react'; // import React, { useState, useMemo, useCallback, useContext } from 'react';
import { ResponsiveSender_defaultProps, ResponsiveReceiver_defaultProps } from "./props/defaultProps";
import { ResponsiveSender_propTypes, ResponsiveReceiver_propTypes } from "./props/propTypes";
import ResizeObserver from "./ResizeObserver";
import DOMRefWrapper from "./RefWrapper";
import { windowResizeObserver } from "./windowResizeObserver";
import { getBreakPointValue, defaultMatcher } from "./utils/"; // const sortedBreackPointKey = [ 'MOBILE_XS', 'MOBILE_S', 'MOBILE_M', 'MOBILE', 'TABLET_S', 'TABLET_M', 'TABLET', 'LAPTOP_S', 'LAPTOP_M', 'LAPTOP', 'MONITOR_M', 'MONITOR'];
export const ResponsiveContext = /*#__PURE__*/React.createContext({});
const defaultResponsiveId = 'parentReceiver';
export class ResponsiveSender extends React.Component {
constructor(props) {
super(props); // method binding
this.onResize = this.onResize.bind(this);
this.containerRef = this.containerRef.bind(this);
this.getWidth = this.getWidth.bind(this);
this.state = {
breakPoint: null,
getWidth: this.getWidth
}; // variables
this.observer = new ResizeObserver(this.onResize);
this.size = null;
}
getWidth() {
if (!this.size) {
return 0;
}
const {
width
} = this.size;
return width;
}
onResize(size) {
// const { matcher } = this.props;
const {
breakPoint
} = this.state;
const newBreakPoint = defaultMatcher(size);
this.size = size;
if (breakPoint !== newBreakPoint) {
this.setState({
breakPoint: newBreakPoint
});
}
}
containerRef(node) {
this.observer.replaceObservationElement(node);
}
isChanged(data, key) {
this.memo = this.memo || {};
const changed = this.memo[key] !== data;
this.memo[key] = data;
return changed;
}
render() {
const parentContext = this.context;
const {
children,
domRefKey,
responsiveId
} = this.props;
let {
childContext
} = this; // NOTE: this method called here ,Because of we must update local memo.
const isStateChanged = this.isChanged(this.state, 'state');
if (this.isChanged(this.context, 'context') || isStateChanged) {
childContext = Object.assign({}, parentContext);
childContext[responsiveId] = this.state;
childContext[defaultResponsiveId] = this.state; // NOTE: this for fallback of if responsive receiver id wrong
}
this.childContext = childContext;
return /*#__PURE__*/React.createElement(ResponsiveContext.Provider, {
value: childContext
}, /*#__PURE__*/React.createElement(DOMRefWrapper, {
domRefKey: domRefKey,
ref: this.containerRef
}, children));
}
}
ResponsiveSender.defaultProps = { ...ResponsiveSender_defaultProps,
responsiveId: defaultResponsiveId
};
ResponsiveSender.contextType = ResponsiveContext;
ResponsiveSender.propTypes = ResponsiveSender_propTypes;
export function useResponsiveReceiver() {
let responsiveId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultResponsiveId;
const [_, forceUpdate] = useState();
let totalContextData = useContext(ResponsiveContext);
let contextData = totalContextData[responsiveId] || totalContextData[defaultResponsiveId]; // NOTE: this for fallback of if responsive receiver id wrong
let data = contextData;
useEffect(() => {
!contextData && windowResizeObserver.observe(forceUpdate);
return () => !contextData && windowResizeObserver.unobserve(forceUpdate);
}, [!!contextData]);
if (!contextData) {
data = {
breakPoint: windowResizeObserver.getBreackPoint(),
getWidth: () => windowResizeObserver.getSize().width
};
}
const {
breakPoint,
getWidth
} = data;
const childArg = useMemo(() => {
const isTouchDevice = 'ontouchstart' in window && navigator.userAgent.match(/mobi/i) ? true : false;
return {
breakPoint,
isTouchDevice,
deviceBetween(breakPoint1, breakPoint2) {
const width = getWidth();
if (!width) {
return false;
} // const smallBreakPointIndex = sortedBreackPointKey.indexOf(breakPoint1);
// const value1 = smallBreakPointIndex < 1 ? 0 : getBreakPointValue(sortedBreackPointKey[smallBreakPointIndex-1]);
const value1 = getBreakPointValue(breakPoint1);
const value2 = getBreakPointValue(breakPoint2);
if (value1 > value2) {
return this.deviceBetween(breakPoint2, breakPoint1);
}
return value1 <= width && value2 >= width || breakPoint1 === breakPoint || breakPoint2 === breakPoint;
},
deviceOnly() {
let breakPoints = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
return breakPoints.includes(breakPoint);
},
deviceUpto(breakPoint) {
const width = getWidth();
if (!width) {
return false;
}
return width <= getBreakPointValue(breakPoint);
}
};
}, [breakPoint, getWidth]);
return childArg;
} // function ResponsiveReceiverFunc({ children, hiddenSizes }, ref) {
// const { breakPoint, methods } = useResponsiveReceiver();
// console.log(hiddenSizes);
// return hiddenSizes.indexOf(breakPoint) === -1 ? (
// <RefWrapper ref={ref}>{children(breakPoint, methods)}</RefWrapper>
// ) : null;
// }
export function ResponsiveReceiver(_ref) {
let {
children,
responsiveId,
hiddenSizes,
eleRef,
domRefKey
} = _ref;
const data = useResponsiveReceiver(responsiveId);
const {
breakPoint
} = data;
const child = children(data);
return !hiddenSizes.includes(breakPoint) ? eleRef ? /*#__PURE__*/React.createElement(DOMRefWrapper, {
domRefKey: domRefKey,
ref: eleRef
}, child) : child : null;
}
ResponsiveReceiver.defaultProps = { ...ResponsiveReceiver_defaultProps,
responsiveId: defaultResponsiveId
};
ResponsiveReceiver.propTypes = ResponsiveReceiver_propTypes;