UNPKG

@zohodesk/components

Version:

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

194 lines (164 loc) 6.11 kB
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;