From 181d058b9154732b0aab0679ddb4f7e0a84e90eb Mon Sep 17 00:00:00 2001 From: John Wright Date: Wed, 9 Sep 2020 15:26:23 +1000 Subject: [PATCH] feat: add useDocumentElement option --- .storybook/stories/index.js | 70 ++++++++++++++++++++++++++++++++++++- README.md | 32 +++++++++++------ src/SizesContext.js | 1 + src/utils/getWindowSizes.js | 21 +++++++++-- src/withSizes.js | 24 +++++++++---- 5 files changed, 126 insertions(+), 22 deletions(-) diff --git a/.storybook/stories/index.js b/.storybook/stories/index.js index 00ffdf9..caad926 100644 --- a/.storybook/stories/index.js +++ b/.storybook/stories/index.js @@ -5,7 +5,7 @@ import MobileBreakpoint from '../components/MobileBreakpoint' import withSizes from '../../src/withSizes' import SizesProvider from '../../src/SizesProvider' -const mapSizesToProps = sizes => ({ +const mapSizesToProps = (sizes) => ({ backgroundColor: sizes.width > 800 ? 'green' : 'blue', isMobile: withSizes.isMobile(sizes), isTablet: withSizes.isTablet(sizes), @@ -25,6 +25,73 @@ const ExampleSizedComponent = withSizes(mapSizesToProps)( ) ) +class DocumentElementExample extends React.Component { + state = { + windowWidth: window.innerWidth, + documentWidth: document.documentElement.clientWidth, + } + + constructor(...args) { + super(...args) + this.resetState = this.resetState.bind(this) + } + + resetState() { + this.setState({ + windowWidth: window.innerWidth, + documentWidth: document.documentElement.clientWidth, + }) + } + + componentDidMount() { + window.addEventListener('resize', this.resetState) + this.resetState() + } + + componentWillUnmount() { + window.removeEventListener('resize', this.resetState) + } + + render() { + return ( + <> + + + + + + + + + + + + + + + + + +
+
window.innerWidth
+
+
document.documentElement.clientWidth
+
+
{this.state.windowWidth}
+
+
{this.state.documentWidth}
+
+
+
+ + ) + } +} + class ForceFallbackExample extends React.Component { state = { forceFallback: true, @@ -82,6 +149,7 @@ const ExampleSizedComponent = withSizes(mapSizesToProps)( )) + .add('useDocumentElement', () => ) .add('mobileBreakpoint', () => (
diff --git a/README.md b/README.md index 615762e..913a019 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ const MyComponent = enhancer(({ isMobile, counter, setCounter }) => (
Count: {counter}{' '} - +
{isMobile ? 'Is Mobile' : 'Is Not Mobile'}
@@ -154,14 +154,14 @@ withSizes.isMobile = ({ width }) => width < 480 withSizes.isTablet = ({ width }) => width >= 480 && width < 1024 withSizes.isDesktop = ({ width }) => width >= 1024 -withSizes.isGtMobile = sizes => !withSizes.isMobile(sizes) -withSizes.isGtTablet = sizes => withSizes.isDesktop(sizes) +withSizes.isGtMobile = (sizes) => !withSizes.isMobile(sizes) +withSizes.isGtTablet = (sizes) => withSizes.isDesktop(sizes) -withSizes.isStTablet = sizes => withSizes.isMobile(sizes) -withSizes.isStDesktop = sizes => !withSizes.isStDesktop(sizes) +withSizes.isStTablet = (sizes) => withSizes.isMobile(sizes) +withSizes.isStDesktop = (sizes) => !withSizes.isStDesktop(sizes) -withSizes.isTabletAndGreater = sizes => !withSizes.isMobile(sizes) -withSizes.isTabletAndSmaller = sizes => !withSizes.isStDesktop(sizes) +withSizes.isTabletAndGreater = (sizes) => !withSizes.isMobile(sizes) +withSizes.isTabletAndSmaller = (sizes) => !withSizes.isStDesktop(sizes) ``` If it don't fit to your needs, you can create your own selectors. @@ -174,7 +174,7 @@ export const backgroundColor = ({ width }) => (width < 480 ? 'red' : 'green') // your component import { isntDesktop, backgroundColor } from 'utils/sizes/selectors' -const mapSizesToProps = sizes => ({ +const mapSizesToProps = (sizes) => ({ canDisplayMobileFeature: isntDesktop(sizes), backgroundColor: backgroundColor(sizes), }) @@ -182,6 +182,16 @@ const mapSizesToProps = sizes => ({ > `sizes` argument is an object with `width` and `height` properties and represents DOM window width and height. +## Window Width Resource + +By default react-sizes will use `window.innerWidth` to determine the width of the current window. This will also take in to account a body scroll bar. If you'd rather ignore the body's scrollbar and base the size on the document's client width, pass the `useDocumentElement` option: + +```jsx + + + +``` + ## Guide #### mapSizesToProps(sizes) @@ -189,7 +199,7 @@ const mapSizesToProps = sizes => ({ `sizes` argument is an object with `width` and `height` of DOM window. ```js -const mapSizesToProps = sizes => { +const mapSizesToProps = (sizes) => { console.log(sizes) // { width: 1200, height: 720 } (example) } ``` @@ -197,7 +207,7 @@ const mapSizesToProps = sizes => { In pratice, it is a callback that return props that will injected into your Component. ```js -const mapSizesToProps = function(sizes) { +const mapSizesToProps = function (sizes) { const props = { backgroundColor: sizes.width < 700 ? 'red' : 'green', } @@ -238,7 +248,7 @@ import Express from 'express' import { SizesProvider } from 'react-sizes' // All other imports -const getSizesFallback = userAgent => { +const getSizesFallback = (userAgent) => { const md = new MobileDetect(userAgent) if (!!md.mobile()) { diff --git a/src/SizesContext.js b/src/SizesContext.js index d397ebe..3ab9c1b 100644 --- a/src/SizesContext.js +++ b/src/SizesContext.js @@ -1,6 +1,7 @@ import React from 'react' const SizesContext = React.createContext({ + useDocumentElement: false, fallbackWidth: null, fallbackHeight: null, forceFallback: false, diff --git a/src/utils/getWindowSizes.js b/src/utils/getWindowSizes.js index f71171b..994c103 100644 --- a/src/utils/getWindowSizes.js +++ b/src/utils/getWindowSizes.js @@ -1,9 +1,24 @@ -const getWindowSizes = ({ fallbackWidth = null, fallbackHeight = null, forceFallback = false }) => { +const getWindowSizes = ({ + useDocumentElement = false, + fallbackWidth = null, + fallbackHeight = null, + forceFallback = false, +}) => { const canUseDOM = typeof window !== 'undefined' return { - width: canUseDOM && !forceFallback ? window.innerWidth : fallbackWidth, - height: canUseDOM && !forceFallback ? window.innerHeight : fallbackHeight, + width: + canUseDOM && !forceFallback + ? useDocumentElement + ? document.documentElement.clientWidth + : window.innerWidth + : fallbackWidth, + height: + canUseDOM && !forceFallback + ? useDocumentElement + ? document.documentElement.clientHeight + : window.innerHeight + : fallbackHeight, canUseDOM, } } diff --git a/src/withSizes.js b/src/withSizes.js index ef7fb16..6fbf911 100644 --- a/src/withSizes.js +++ b/src/withSizes.js @@ -9,15 +9,25 @@ import getWindowSizes from './utils/getWindowSizes' import SizesContext from './SizesContext' import * as presets from './presets' -const getWindowSizesWithFallback = props => { - const { fallbackHeight, fallbackWidth, forceFallback } = props - return getWindowSizes({ fallbackHeight, fallbackWidth, forceFallback }) +const getWindowSizesWithFallback = (props) => { + const { + useDocumentElement, + fallbackHeight, + fallbackWidth, + forceFallback, + } = props + return getWindowSizes({ + useDocumentElement, + fallbackHeight, + fallbackWidth, + forceFallback, + }) } -const withSizes = (...mappedSizesToProps) => WrappedComponent => { +const withSizes = (...mappedSizesToProps) => (WrappedComponent) => { const parseMappedSizesToProps = (dimensions, props) => mappedSizesToProps - .map(check => check(dimensions, props)) + .map((check) => check(dimensions, props)) .reduce((acc, props) => ({ ...acc, ...props }), {}) class ComponentWithSizes extends PureComponent { @@ -85,9 +95,9 @@ const withSizes = (...mappedSizesToProps) => WrappedComponent => { } } - const WithSizes = props => ( + const WithSizes = (props) => ( - {config => } + {(config) => } )