diff --git a/README.md b/README.md index 71ae809..5c30ee3 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@

- +

Make your React Components aware of their width and height

+

[![Travis](https://img.shields.io/travis/ctrlplusb/react-sizeme.svg?style=flat-square)](https://travis-ci.org/ctrlplusb/react-sizeme) [![npm](https://img.shields.io/npm/v/react-sizeme.svg?style=flat-square)](http://npm.im/react-sizeme) [![MIT License](https://img.shields.io/npm/l/react-sizeme.svg?style=flat-square)](http://opensource.org/licenses/MIT) @@ -16,6 +17,20 @@ * Works with React 0.14.x and 15.x.x. * 7.67KB gzipped standalone, even smaller if bundled into your own project. + +## Index + + - [Release Notes](https://github.com/ctrlplusb/react-sizeme#release-notes) + - [What is this for?](https://github.com/ctrlplusb/react-sizeme#what-is-this-for) + - [Live Demo](https://github.com/ctrlplusb/react-sizeme#live-demo) + - [Simple Example](https://github.com/ctrlplusb/react-sizeme#simple-example) + - [Usage and API Details](https://github.com/ctrlplusb/react-sizeme#usage-and-api-details) + - [On the First Render of your Component](https://github.com/ctrlplusb/react-sizeme#on-the-first-render-of-your-component) + - [Things to Consider](https://github.com/ctrlplusb/react-sizeme#things-to-consider) + - [Server Side Rendering](https://github.com/ctrlplusb/react-sizeme#server-side-rendering) + - [Extreme Appreciation](https://github.com/ctrlplusb/react-sizeme#extreme-appreciation) + + ## Release Notes See here: https://github.com/ctrlplusb/react-sizeme/releases @@ -213,10 +228,23 @@ The intention of this library to aid in initial render on a target device, i.e. If however you wish to use this library to wrap a component that you expect to be resized via user/system actions then I would recommend that you consider setting the `refreshRate` to a higher setting so that you don't spam the browser with updates. -## Caveats. +## Server Side Rendering + +Okay, I am gonna be up front here and tell you that using this library in an SSR context is most likely a bad idea. However, if you insist on doing so you then you should take the time to make yourself fully aware of any possible repurcussions you application may face. + +A standard `SizeMe` configuration involves the rendering of a placeholder component. After the placeholder is mounted to the DOM we extract it's dimension information and pass it on to your actual component. We do this in order to avoid any unneccesary render cycles for possibly deep component trees. Whilst this is useful for a purely client side set up, this is less than useful for an SSR context as the delivered page will contain empty placeholders. Ideally you want actual content to be delivered so that users without JS can still have an experience, or SEO bots can scrape your website. + +Therefore we have provided a global configuration flag on `SizeMe`. Setting this flag will switch the library into an SSR mode, which essentially disables any placeholder rendering. Instead your wrapped component will be rendered directly. You should set the flag within the initialisation of your application (for both client/server). + +```javascript +import SizeMe from 'react-sizeme'; + +SizeMe.enableSSRBehaviour = true; // default is false +``` + +In a server context we can't know the width/height of your component so you will simply receive `null` values for both. It is up to you to decide how you would like to render your component then. When your component is sent to the client and mounted to the DOM `SizeMe` will calculate and send the dimensions to your component as normal. I suggest you tread very carefully with how you use this updated information and do lots of testing using various screen dimensions. Try your best to avoid unnecessary re-rendering of your components, for the sake of your users. -* Server Side Rendering is not supported (yet). Keep track of this in issue #7. -* Whilst execution is performant and we try and do smart rendering mechanisms we don't recommend that you place a crazy amount of size aware components into your render tree. If you do require this I highly recommend you do some decent browser testing for impact. +If you come up with any clever strategies for this please do come share them with us! :) ## Extreme Appreciation! diff --git a/lib/react-sizeme.js b/lib/react-sizeme.js index a86c392..e0c3386 100644 --- a/lib/react-sizeme.js +++ b/lib/react-sizeme.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react"),require("react-dom")):"function"==typeof define&&define.amd?define("react-sizeme",["react","react-dom"],t):"object"==typeof exports?exports["react-sizeme"]=t(require("react"),require("react-dom")):e["react-sizeme"]=t(e.React,e.ReactDOM)}(this,function(e,t){return function(e){function t(i){if(n[i])return n[i].exports;var r=n[i]={exports:{},id:i,loaded:!1};return e[i].call(r.exports,r,r.exports,t),r.loaded=!0,r.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n(4),o=i(r);t.default=o.default},function(e,t){"use strict";var n=e.exports={};n.isIE=function(e){function t(){var e=navigator.userAgent.toLowerCase();return-1!==e.indexOf("msie")||-1!==e.indexOf("trident")||-1!==e.indexOf(" edge/")}if(!t())return!1;if(!e)return!0;var n=function(){var e,t=3,n=document.createElement("div"),i=n.getElementsByTagName("i");do n.innerHTML="";while(i[0]);return t>4?t:e}();return e===n},n.isLegacyOpera=function(){return!!window.opera}},function(e,t){"use strict";var n=e.exports={};n.forEach=function(e,t){for(var n=0;e.length>n;n++){var i=t(e[n]);if(i)return i}}},function(e,t){function n(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}e.exports=n},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{"default":e}}function r(e,t){var n={};for(var i in e)t.indexOf(i)<0&&Object.prototype.hasOwnProperty.call(e,i)&&(n[i]=e[i]);return n}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function a(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function s(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e){return e.displayName||e.name||"Component"}function c(e){var t=e.className,n=e.style,i={};return t||n?(t&&(i.className=t),n&&(i.style=n)):i.style={width:"100%",height:"100%",position:"relative"},g.default.createElement("div",i)}function u(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:S,t=e.monitorWidth,n=void 0===t?!0:t,i=e.monitorHeight,r=void 0===i?!1:i,c=e.refreshRate,u=void 0===c?16:c;return(0,w.default)(n||r,'You have to monitor at least one of the width or height when using the "sizeAware" higher order component'),(0,w.default)(u>=16,"It is highly recommended that you don't put your refreshRate lower than 16 as this may cause layout thrashing."),function(e){var t=T(e),i=function(e){function i(){var e,t,s,l;o(this,i);for(var c=arguments.length,d=Array(c),h=0;c>h;h++)d[h]=arguments[h];return t=s=a(this,(e=Object.getPrototypeOf(i)).call.apply(e,[this].concat(d))),s.state={width:void 0,height:void 0},s.refCallback=function(e){s.element=e},s.hasSizeChanged=function(e,t){var i=e.height,o=e.width,a=t.height,s=t.width;return r&&i!==a||n&&o!==s},s.checkIfSizeChanged=(0,f.default)(function(e){var t=e.getBoundingClientRect(),i=t.width,o=t.height,a={width:n?i:null,height:r?o:null};s.hasSizeChanged(s.state,a)&&s.setState(a)},u),l=t,a(s,l)}return s(i,e),p(i,[{key:"componentDidMount",value:function(){this.handleDOMNode()}},{key:"componentDidUpdate",value:function(){this.handleDOMNode()}},{key:"componentWillUnmount",value:function(){this.hasSizeChanged=function(){},this.checkIfSizeChanged=function(){},this.domEl&&(E.default.removeAllListeners(this.domEl),this.domEl=null)}},{key:"handleDOMNode",value:function(){var e=this.element&&y.default.findDOMNode(this.element);return e?(this.domEl&&E.default.removeAllListeners(this.domEl),this.domEl=e,void E.default.listenTo(this.domEl,this.checkIfSizeChanged)):void(this.domEl&&(E.default.removeAllListeners(this.domEl),this.domEl=null))}},{key:"render",value:function(){var e=this.state,n=e.width,i=e.height;return g.default.createElement(t,h({explicitRef:this.refCallback,size:{width:n,height:i}},this.props))}}]),i}(g.default.Component);return i.displayName="SizeMe("+l(e)+")",i}}Object.defineProperty(t,"__esModule",{value:!0});var d=n(20),f=i(d),h=Object.assign||function(e){for(var t=1;arguments.length>t;t++){var n=arguments[t];for(var i in n)Object.prototype.hasOwnProperty.call(n,i)&&(e[i]=n[i])}return e},p=function(){function e(e,t){for(var n=0;t.length>n;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}(),v=n(22),g=i(v),m=n(23),y=i(m),b=n(17),w=i(b),x=n(5),E=i(x),S={monitorWidth:!0,monitorHeight:!1},z=function(e){function t(){return o(this,t),a(this,Object.getPrototypeOf(t).apply(this,arguments))}return s(t,e),p(t,[{key:"render",value:function(){return v.Children.only(this.props.children)}}]),t}(v.Component);z.displayName="SizeMeReferenceWrapper",z.propTypes={children:v.PropTypes.element.isRequired},c.displayName="SizeMePlaceholder",c.propTypes={className:v.PropTypes.string,style:v.PropTypes.object};var T=function(e){function t(t){var n=t.explicitRef,i=t.className,o=t.style,a=t.size,s=r(t,["explicitRef","className","style","size"]),l=a.width,u=a.height,d=void 0===l&&void 0===u?g.default.createElement(c,{className:i,style:o}):g.default.createElement(e,h({className:i,style:o,size:a},s));return g.default.createElement(z,{ref:n},d)}return t.displayName="SizeMeRenderer("+l(e)+")",t.propTypes={explicitRef:v.PropTypes.func.isRequired,className:v.PropTypes.string,style:v.PropTypes.object,size:v.PropTypes.shape({width:v.PropTypes.number,height:v.PropTypes.number})},t};t.default=u},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var r=n(10),o=i(r),a=(0,o.default)({strategy:"scroll"});t.default=a},function(e,t,n){"use strict";function i(){function e(e,t){t||(t=e,e=0),e>o?o=e:a>e&&(a=e),i[e]||(i[e]=[]),i[e].push(t),r++}function t(){for(var e=a;o>=e;e++)for(var t=i[e],n=0;t.length>n;n++){var r=t[n];r()}}function n(){return r}var i={},r=0,o=0,a=0;return{add:e,process:t,size:n}}var r=n(7);e.exports=function(e){function t(e,t){!p&&d&&u&&0===h.size()&&a(),h.add(e,t)}function n(){for(p=!0;h.size();){var e=h;h=i(),e.process()}p=!1}function o(e){p||(void 0===e&&(e=u),f&&(s(f),f=null),e?a():n())}function a(){f=l(n)}function s(e){var t=clearTimeout;return t(e)}function l(e){var t=function(e){return setTimeout(e,0)};return t(e)}e=e||{};var c=e.reporter,u=r.getOption(e,"async",!0),d=r.getOption(e,"auto",!0);d&&!u&&(c&&c.warn("Invalid options combination. auto=true and async=false is invalid. Setting async=true."),u=!0);var f,h=i(),p=!1;return{add:t,force:o}}},function(e,t){"use strict";function n(e,t,n){var i=e[t];return void 0!==i&&null!==i||void 0===n?i:n}var i=e.exports={};i.getOption=n},function(e,t,n){"use strict";var i=n(1);e.exports=function(e){function t(e,t){function n(){t(e)}if(!r(e))throw Error("Element is not detectable by this strategy.");if(i.isIE(8))l(e).object={proxy:n},e.attachEvent("onresize",n);else{var o=r(e);o.contentDocument.defaultView.addEventListener("resize",n)}}function n(e,t,n){function r(e,t){function n(){function n(){if("static"===c.position){e.style.position="relative";var t=function(e,t,n,i){function r(e){return e.replace(/[^-\d\.]/g,"")}var o=n[i];"auto"!==o&&"0"!==r(o)&&(e.warn("An element that is positioned static has style."+i+"="+o+" which is ignored due to the static positioning. The element will need to be positioned relative, so the style."+i+" will be set to 0. Element: ",t),t.style[i]=0)};t(a,e,c,"top"),t(a,e,c,"right"),t(a,e,c,"bottom"),t(a,e,c,"left")}}function s(){function i(e,t){return e.contentDocument?void t(e.contentDocument):void setTimeout(function(){i(e,t)},100)}o||n();var r=this;i(r,function(n){t(e)})}""!==c.position&&(n(c),o=!0);var u=document.createElement("object");u.style.cssText=r,u.type="text/html",u.onload=s,i.isIE()||(u.data="about:blank"),e.appendChild(u),l(e).object=u,i.isIE()&&(u.data="about:blank")}var r="display: block; position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: none; padding: 0; margin: 0; opacity: 0; z-index: -1000; pointer-events: none;",o=!1,c=window.getComputedStyle(e),u=e.offsetWidth,d=e.offsetHeight;l(e).startSize={width:u,height:d},s?s.add(n):n()}n||(n=t,t=e,e=null),e=e||{};i.isIE(8)?n(t):r(t,n)}function r(e){return l(e).object}function o(e){i.isIE(8)?e.detachEvent("onresize",l(e).object.proxy):e.removeChild(r(e)),delete l(e).object}e=e||{};var a=e.reporter,s=e.batchProcessor,l=e.stateHandler.getState;if(!a)throw Error("Missing required dependency: reporter.");return{makeDetectable:n,addListener:t,uninstall:o}}},function(e,t,n){"use strict";var i=n(2).forEach;e.exports=function(e){function t(){var e=500,t=500,n=document.createElement("div");n.style.cssText="position: absolute; width: "+2*e+"px; height: "+2*t+"px; visibility: hidden;";var i=document.createElement("div");i.style.cssText="position: absolute; width: "+e+"px; height: "+t+"px; overflow: scroll; visibility: none; top: "+3*-e+"px; left: "+3*-t+"px; visibility: hidden;",i.appendChild(n),document.body.insertBefore(i,document.body.firstChild);var r=e-i.clientWidth,o=t-i.clientHeight;return document.body.removeChild(i),{width:r,height:o}}function n(e,t){function n(t,n){n=n||function(e){document.head.appendChild(e)};var i=document.createElement("style");return i.innerHTML=t,i.id=e,n(i),i}if(!document.getElementById(e)){var i=t+"_animation",r=t+"_animation_active",o="/* Created by the element-resize-detector library. */\n";o+="."+t+" > div::-webkit-scrollbar { display: none; }\n\n",o+="."+r+" { -webkit-animation-duration: 0.1s; animation-duration: 0.1s; -webkit-animation-name: "+i+"; animation-name: "+i+"; }\n",o+="@-webkit-keyframes "+i+" { 0% { opacity: 1; } 50% { opacity: 0; } 100% { opacity: 1; } }\n",o+="@keyframes "+i+" { 0% { opacity: 1; } 50% { opacity: 0; } 100% { opacity: 1; } }",n(o)}}function r(e){e.className+=" "+p+"_animation_active"}function o(e,t){var n=u(e).listeners;if(!n.push)throw Error("Cannot add listener to an element that is not detectable.");u(e).listeners.push(t)}function a(e,t,n){function o(){if(e.debug){var n=Array.prototype.slice.call(arguments);if(n.unshift(d.get(t),"Scroll: "),l.log.apply)l.log.apply(null,n);else for(var i=0;n.length>i;i++)l.log(n[i])}}function a(e){function t(e){return e===e.ownerDocument.body||e.ownerDocument.body.contains(e)}return!t(e)}function s(e){var t=u(e).container.childNodes[0];return-1===getComputedStyle(t).width.indexOf("px")}function h(){var e=getComputedStyle(t),n={};return n.position=e.position,n.width=t.offsetWidth,n.height=t.offsetHeight,n.top=e.top,n.right=e.right,n.bottom=e.bottom,n.left=e.left,n.widthCSS=e.width,n.heightCSS=e.height,n}function v(){var e=h();u(t).startSize={width:e.width,height:e.height},o("Element start size",u(t).startSize)}function g(){u(t).listeners=[]}function m(){if(o("storeStyle invoked."),!u(t))return void o("Aborting because element has been uninstalled");var e=h();u(t).style=e}function y(e,t,n){u(e).lastWidth=t,u(e).lastHeight=n}function b(e){return u(e).container.childNodes[0].childNodes[0].childNodes[0]}function w(e){return b(e).childNodes[0]}function x(e){return u(e).container.childNodes[0].childNodes[0].childNodes[1]}function E(){return 2*f.width+1}function S(){return 2*f.height+1}function z(e){return e+10+E()}function T(e){return e+10+S()}function k(e){return 2*e+E()}function O(e){return 2*e+S()}function C(e,t,n){var i=b(e),r=x(e),o=z(t),a=T(n),s=k(t),l=O(n);i.scrollLeft=o,i.scrollTop=a,r.scrollLeft=s,r.scrollTop=l}function N(e,t,n){if(e.addEventListener)e.addEventListener(t,n);else{if(!e.attachEvent)return l.error("[scroll] Don't know how to add event listeners.");e.attachEvent("on"+t,n)}}function j(){var e=u(t).container;return e||(e=document.createElement("div"),e.className=p,e.style.cssText="visibility: hidden; display: inline; width: 0px; height: 0px; z-index: -1; overflow: hidden;",u(t).container=e,r(e),t.appendChild(e),N(e,"animationstart",function(){u(t).onRendered&&u(t).onRendered()})),e}function A(){function e(){var e=u(t).style;if("static"===e.position){t.style.position="relative";var n=function(e,t,n,i){function r(e){return e.replace(/[^-\d\.]/g,"")}var o=n[i];"auto"!==o&&"0"!==r(o)&&(e.warn("An element that is positioned static has style."+i+"="+o+" which is ignored due to the static positioning. The element will need to be positioned relative, so the style."+i+" will be set to 0. Element: ",t),t.style[i]=0)};n(l,t,e,"top"),n(l,t,e,"right"),n(l,t,e,"bottom"),n(l,t,e,"left")}}function n(e,t,n,i){return e=e?e+"px":"0",t=t?t+"px":"0",n=n?n+"px":"0",i=i?i+"px":"0","left: "+e+"; top: "+t+"; right: "+i+"; bottom: "+n+";"}if(o("Injecting elements"),!u(t))return void o("Aborting because element has been uninstalled");e();var i=u(t).container;i||(i=j());var r=f.width,a=f.height,s="position: absolute; overflow: hidden; z-index: -1; visibility: hidden; width: 100%; height: 100%; left: 0px; top: 0px;",c="position: absolute; overflow: hidden; z-index: -1; visibility: hidden; "+n(-(1+r),-(1+a),-a,-r),d="position: absolute; overflow: scroll; z-index: -1; visibility: hidden; width: 100%; height: 100%;",h="position: absolute; overflow: scroll; z-index: -1; visibility: hidden; width: 100%; height: 100%;",v="position: absolute; left: 0; top: 0;",g="position: absolute; width: 200%; height: 200%;",m=document.createElement("div"),y=document.createElement("div"),b=document.createElement("div"),w=document.createElement("div"),x=document.createElement("div"),E=document.createElement("div");m.style.cssText=s,m.className=p,y.className=p,y.style.cssText=c,b.style.cssText=d,w.style.cssText=v,x.style.cssText=h,E.style.cssText=g,b.appendChild(w),x.appendChild(E),y.appendChild(b),y.appendChild(x),m.appendChild(y),i.appendChild(m),N(b,"scroll",function(){u(t).onExpand&&u(t).onExpand()}),N(x,"scroll",function(){u(t).onShrink&&u(t).onShrink()})}function H(){function n(e,t,n){var i=w(e),r=z(t),o=T(n);i.style.width=r+"px",i.style.height=o+"px"}function r(i){var r=t.offsetWidth,a=t.offsetHeight;o("Storing current size",r,a),y(t,r,a),c.add(0,function(){if(e.debug){var i=t.offsetWidth,o=t.offsetHeight;i===r&&o===a||l.warn(d.get(t),"Scroll: Size changed before updating detector elements.")}n(t,r,a)}),c.add(1,function(){C(t,r,a)}),i&&c.add(2,i)}function a(){function e(){return void 0===u(t).lastNotifiedWidth}o("notifyListenersIfNeeded invoked");var n=u(t);return e()&&n.lastWidth===n.startSize.width&&n.lastHeight===n.startSize.height?o("Not notifying: Size is the same as the start size, and there has been no notification yet."):n.lastWidth===n.lastNotifiedWidth&&n.lastHeight===n.lastNotifiedHeight?o("Not notifying: Size already notified"):(o("Current size not notified, notifying..."),n.lastNotifiedWidth=n.lastWidth,n.lastNotifiedHeight=n.lastHeight,void i(u(t).listeners,function(e){e(t)}))}function f(){if(o("startanimation triggered."),s(t))return void o("Ignoring since element is still unrendered...");o("Element rendered.");var e=b(t),n=x(t);0!==e.scrollLeft&&0!==e.scrollTop&&0!==n.scrollLeft&&0!==n.scrollTop||(o("Scrollbars out of sync. Updating detector elements..."),r(a))}function h(){if(o("Scroll detected."),s(t))return void o("Scroll event fired while unrendered. Ignoring...");var e=t.offsetWidth,n=t.offsetHeight;e!==t.lastWidth||n!==t.lastHeight?(o("Element size changed."),r(a)):o("Element size has not changed ("+e+"x"+n+").")}if(o("registerListenersAndPositionElements invoked."),!u(t))return void o("Aborting because element has been uninstalled");u(t).onRendered=f,u(t).onExpand=h,u(t).onShrink=h;var p=u(t).style;n(t,p.width,p.height)}function M(){if(o("finalizeDomMutation invoked."),!u(t))return void o("Aborting because element has been uninstalled");var e=u(t).style;y(t,e.width,e.height),C(t,e.width,e.height)}function _(){n(t)}function L(){o("Installing..."),g(),v(),c.add(0,m),c.add(1,A),c.add(2,H),c.add(3,M),c.add(4,_)}n||(n=t,t=e,e=null),e=e||{},o("Making detectable..."),a(t)?(o("Element is detached"),j(),o("Waiting until element is attached..."),u(t).onRendered=function(){o("Element is now attached"),L()}):L()}function s(e){var t=u(e);t.busy||e.removeChild(t.container)}e=e||{};var l=e.reporter,c=e.batchProcessor,u=e.stateHandler.getState,d=e.idHandler;if(!c)throw Error("Missing required dependency: batchProcessor");if(!l)throw Error("Missing required dependency: reporter.");var f=t(),h="erd_scroll_detection_scrollbar_style",p="erd_scroll_detection_container";return n(h,p),{makeDetectable:a,addListener:o,uninstall:s}}},function(e,t,n){"use strict";function i(e,t,n){var i=e[t];return void 0!==i&&null!==i||void 0===n?i:n}var r=n(2).forEach,o=n(11),a=n(14),s=n(12),l=n(13),c=n(15),u=n(1),d=n(6),f=n(16),h=n(8),p=n(9);e.exports=function(e){function t(e,t,n){function o(e){var t=S.get(e);r(t,function(t){t(e)})}function a(e,t,n){S.add(t,n),e&&n(t)}function s(e){return Array.isArray(e)||void 0!==e.length}function l(e){if(Array.isArray(e))return e;var n=[];return r(t,function(e){n.push(e)}),n}function c(e){return e&&1===e.nodeType}if(n||(n=t,t=e,e={}),!t)throw Error("At least one element required.");if(!n)throw Error("Listener required.");if(c(t))t=[t];else{if(!s(t))return y.error("Invalid arguments. Must be a DOM element or a collection of DOM elements.");t=l(t)}var u=0,d=i(e,"callOnAdd",x.callOnAdd),h=i(e,"onReady",function(){}),p=i(e,"debug",x.debug);r(t,function(e){f.getState(e)||(f.initState(e),v.set(e));var i=v.get(e);return p&&y.log("Attaching listener to element",i,e),z.isDetectable(e)?(p&&y.log(i,"Already detecable, adding listener."),a(d,e,n),void u++):(p&&y.log(i,"Not detectable."),z.isBusy(e)?(p&&y.log(i,"System busy making it detectable"),a(d,e,n),O[i]=O[i]||[],void O[i].push(function(){u++,u===t.length&&h()})):(p&&y.log(i,"Making detectable..."),z.markBusy(e,!0),E.makeDetectable({debug:p},e,function(e){if(p&&y.log(i,"onElementDetectable"),f.getState(e)){if(z.markAsDetectable(e),z.markBusy(e,!1),E.addListener(e,o),a(d,e,n),f.getState(e).startSize){var s=e.offsetWidth,l=e.offsetHeight;f.getState(e).startSize.width===s&&f.getState(e).startSize.height===l||o(e)}O[i]&&r(O[i],function(e){e()})}else p&&y.log(i,"Element uninstalled before being detectable.");delete O[i],u++,u===t.length&&h()})))}),u===t.length&&h()}function n(e){S.removeAllListeners(e),E.uninstall(e),f.cleanState(e)}e=e||{};var v;if(e.idHandler)v={get:function(t){e.idHandler.get(t,!0)},set:e.idHandler.set};else{var g=s(),m=l({idGenerator:g,stateHandler:f});v=m}var y=e.reporter;if(!y){var b=y===!1;y=c(b)}var w=i(e,"batchProcessor",d({reporter:y})),x={};x.callOnAdd=!!i(e,"callOnAdd",!0),x.debug=!!i(e,"debug",!1);var E,S=a(v),z=o({stateHandler:f}),T=i(e,"strategy","object"),k={reporter:y,batchProcessor:w,stateHandler:f,idHandler:v};if("scroll"===T&&(u.isLegacyOpera()?(y.warn("Scroll strategy is not supported on legacy Opera. Changing to object strategy."),T="object"):u.isIE(9)&&(y.warn("Scroll strategy is not supported on IE9. Changing to object strategy."),T="object")),"scroll"===T)E=p(k);else{if("object"!==T)throw Error("Invalid strategy name: "+T);E=h(k)}var O={};return{listenTo:t,removeListener:S.removeListener,removeAllListeners:S.removeAllListeners,uninstall:n}}},function(e,t){"use strict";e.exports=function(e){function t(e){var t=o(e);return t&&!!t.isDetectable}function n(e){o(e).isDetectable=!0}function i(e){return!!o(e).busy}function r(e,t){o(e).busy=!!t}var o=e.stateHandler.getState;return{isDetectable:t,markAsDetectable:n,isBusy:i,markBusy:r}}},function(e,t){"use strict";e.exports=function(){function e(){return t++}var t=1;return{generate:e}}},function(e,t){"use strict";e.exports=function(e){function t(e){var t=r(e);return t&&void 0!==t.id?t.id:null}function n(e){var t=r(e);if(!t)throw Error("setId required the element to have a resize detection state.");var n=i.generate();return t.id=n,n}var i=e.idGenerator,r=e.stateHandler.getState;return{get:t,set:n}}},function(e,t){"use strict";e.exports=function(e){function t(t){return o[e.get(t)]||[]}function n(t,n){var i=e.get(t);o[i]||(o[i]=[]),o[i].push(n)}function i(e,n){for(var i=t(e),r=0,o=i.length;o>r;++r)if(i[r]===n){i.splice(r,1);break}}function r(t){var n=o[e.get(t)];n&&(n.length=0)}var o={};return{get:t,add:n,removeListener:i,removeAllListeners:r}}},function(e,t){"use strict";e.exports=function(e){function t(){}var n={log:t,warn:t,error:t};if(!e&&window.console){var i=function(e,t){e[t]=function(){var e=console[t];if(e.apply)e.apply(console,arguments);else for(var n=0;arguments.length>n;n++)e(arguments[n])}};i(n,"log"),i(n,"warn"),i(n,"error")}return n}},function(e,t){"use strict";function n(e){return e[o]={},i(e)}function i(e){return e[o]}function r(e){delete e[o]}var o="_erd";e.exports={initState:n,getState:i,cleanState:r}},function(e,t,n){"use strict";var i=function(e,t,n,i,r,o,a,s){if(!e){var l;if(void 0===t)l=Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var c=[n,i,r,o,a,s],u=0;l=Error(t.replace(/%s/g,function(){return c[u++]})),l.name="Invariant Violation"}throw l.framesToPop=1,l}};e.exports=i},function(e,t,n){function i(e,t,n){function i(t){var n=y,i=b;return y=b=void 0,z=t,x=e.apply(i,n)}function u(e){return z=e,E=setTimeout(h,t),T?i(e):x}function d(e){var n=e-S,i=e-z,r=t-n;return k?c(r,w-i):r}function f(e){var n=e-S,i=e-z;return!S||n>=t||0>n||k&&i>=w}function h(){var e=o();return f(e)?p(e):void(E=setTimeout(h,d(e)))}function p(e){return clearTimeout(E),E=void 0,O&&y?i(e):(y=b=void 0,x)}function v(){void 0!==E&&clearTimeout(E),S=z=0,y=b=E=void 0}function g(){return void 0===E?x:p(o())}function m(){var e=o(),n=f(e);if(y=arguments,b=this,S=e,n){if(void 0===E)return u(S);if(k)return clearTimeout(E),E=setTimeout(h,t),i(S)}return void 0===E&&(E=setTimeout(h,t)),x}var y,b,w,x,E,S=0,z=0,T=!1,k=!1,O=!0;if("function"!=typeof e)throw new TypeError(s);return t=a(t)||0,r(n)&&(T=!!n.leading,k="maxWait"in n,w=k?l(a(n.maxWait)||0,t):w,O="trailing"in n?!!n.trailing:O),m.cancel=v,m.flush=g,m}var r=n(3),o=n(19),a=n(21),s="Expected a function",l=Math.max,c=Math.min;e.exports=i},function(e,t){var n=Date.now;e.exports=n},function(e,t,n){function i(e,t,n){var i=!0,s=!0;if("function"!=typeof e)throw new TypeError(a);return o(n)&&(i="leading"in n?!!n.leading:i,s="trailing"in n?!!n.trailing:s),r(e,t,{leading:i,maxWait:t,trailing:s})}var r=n(18),o=n(3),a="Expected a function";e.exports=i},function(e,t){function n(e){return e}e.exports=n},function(t,n){t.exports=e},function(e,n){e.exports=t}])}); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react"),require("react-dom")):"function"==typeof define&&define.amd?define("react-sizeme",["react","react-dom"],t):"object"==typeof exports?exports["react-sizeme"]=t(require("react"),require("react-dom")):e["react-sizeme"]=t(e.React,e.ReactDOM)}(this,function(e,t){return function(e){function t(i){if(n[i])return n[i].exports;var r=n[i]={exports:{},id:i,loaded:!1};return e[i].call(r.exports,r,r.exports,t),r.loaded=!0,r.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n(4),o=i(r);t.default=o.default},function(e,t){"use strict";var n=e.exports={};n.isIE=function(e){function t(){var e=navigator.userAgent.toLowerCase();return-1!==e.indexOf("msie")||-1!==e.indexOf("trident")||-1!==e.indexOf(" edge/")}if(!t())return!1;if(!e)return!0;var n=function(){var e,t=3,n=document.createElement("div"),i=n.getElementsByTagName("i");do n.innerHTML="";while(i[0]);return t>4?t:e}();return e===n},n.isLegacyOpera=function(){return!!window.opera}},function(e,t){"use strict";var n=e.exports={};n.forEach=function(e,t){for(var n=0;e.length>n;n++){var i=t(e[n]);if(i)return i}}},function(e,t){function n(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}e.exports=n},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{"default":e}}function r(e,t){var n={};for(var i in e)t.indexOf(i)<0&&Object.prototype.hasOwnProperty.call(e,i)&&(n[i]=e[i]);return n}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function a(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function s(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e){return e.displayName||e.name||"Component"}function c(e){var t=e.className,n=e.style,i={};return t||n?(t&&(i.className=t),n&&(i.style=n)):i.style={width:"100%",height:"100%",position:"relative"},g.default.createElement("div",i)}function u(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:S,t=e.monitorWidth,n=void 0===t?!0:t,i=e.monitorHeight,r=void 0===i?!1:i,c=e.refreshRate,d=void 0===c?16:c;return(0,w.default)(n||r,'You have to monitor at least one of the width or height when using the "sizeAware" higher order component'),(0,w.default)(d>=16,"It is highly recommended that you don't put your refreshRate lower than 16 as this may cause layout thrashing."),function(e){var t=T(e),i=function(e){function i(){var e,t,s,l;o(this,i);for(var c=arguments.length,u=Array(c),h=0;c>h;h++)u[h]=arguments[h];return t=s=a(this,(e=Object.getPrototypeOf(i)).call.apply(e,[this].concat(u))),s.state={width:void 0,height:void 0},s.refCallback=function(e){s.element=e},s.hasSizeChanged=function(e,t){var i=e.height,o=e.width,a=t.height,s=t.width;return r&&i!==a||n&&o!==s},s.checkIfSizeChanged=(0,f.default)(function(e){var t=e.getBoundingClientRect(),i=t.width,o=t.height,a={width:n?i:null,height:r?o:null};s.hasSizeChanged(s.state,a)&&s.setState(a)},d),l=t,a(s,l)}return s(i,e),p(i,[{key:"componentDidMount",value:function(){this.handleDOMNode()}},{key:"componentDidUpdate",value:function(){this.handleDOMNode()}},{key:"componentWillUnmount",value:function(){this.hasSizeChanged=function(){},this.checkIfSizeChanged=function(){},this.domEl&&((0,E.default)().removeAllListeners(this.domEl),this.domEl=null)}},{key:"handleDOMNode",value:function(){var e=this.element&&y.default.findDOMNode(this.element);return e?(this.domEl&&(0,E.default)().removeAllListeners(this.domEl),this.domEl=e,void(0,E.default)().listenTo(this.domEl,this.checkIfSizeChanged)):void(this.domEl&&((0,E.default)().removeAllListeners(this.domEl),this.domEl=null))}},{key:"render",value:function(){var e=this.state,n=e.width,i=e.height;return g.default.createElement(t,h({explicitRef:this.refCallback,size:{width:n,height:i},disablePlaceholder:!!u.enableSSRBehaviour},this.props))}}]),i}(g.default.Component);return i.displayName="SizeMe("+l(e)+")",i}}Object.defineProperty(t,"__esModule",{value:!0});var d=n(20),f=i(d),h=Object.assign||function(e){for(var t=1;arguments.length>t;t++){var n=arguments[t];for(var i in n)Object.prototype.hasOwnProperty.call(n,i)&&(e[i]=n[i])}return e},p=function(){function e(e,t){for(var n=0;t.length>n;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}(),v=n(22),g=i(v),m=n(23),y=i(m),b=n(17),w=i(b),x=n(5),E=i(x),S={monitorWidth:!0,monitorHeight:!1},z=function(e){function t(){return o(this,t),a(this,Object.getPrototypeOf(t).apply(this,arguments))}return s(t,e),p(t,[{key:"render",value:function(){return v.Children.only(this.props.children)}}]),t}(v.Component);z.displayName="SizeMeReferenceWrapper",z.propTypes={children:v.PropTypes.element.isRequired},c.displayName="SizeMePlaceholder",c.propTypes={className:v.PropTypes.string,style:v.PropTypes.object};var T=function(e){function t(t){var n=t.explicitRef,i=t.className,o=t.style,a=t.size,s=t.disablePlaceholder,l=r(t,["explicitRef","className","style","size","disablePlaceholder"]),u=a.width,d=a.height,f=void 0!==u||void 0!==d||s?g.default.createElement(e,h({className:i,style:o,size:a},l)):g.default.createElement(c,{className:i,style:o});return g.default.createElement(z,{ref:n},f)}return t.displayName="SizeMeRenderer("+l(e)+")",t.propTypes={explicitRef:v.PropTypes.func.isRequired,className:v.PropTypes.string,style:v.PropTypes.object,size:v.PropTypes.shape({width:v.PropTypes.number,height:v.PropTypes.number}),disablePlaceholder:v.PropTypes.bool},t};u.enableSSRBehaviour=!1,t.default=u},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{"default":e}}function r(){return s||(s=(0,a.default)({strategy:"scroll"})),s}Object.defineProperty(t,"__esModule",{value:!0});var o=n(10),a=i(o),s=void 0;t.default=r},function(e,t,n){"use strict";function i(){function e(e,t){t||(t=e,e=0),e>o?o=e:a>e&&(a=e),i[e]||(i[e]=[]),i[e].push(t),r++}function t(){for(var e=a;o>=e;e++)for(var t=i[e],n=0;t.length>n;n++){var r=t[n];r()}}function n(){return r}var i={},r=0,o=0,a=0;return{add:e,process:t,size:n}}var r=n(7);e.exports=function(e){function t(e,t){!p&&d&&u&&0===h.size()&&a(),h.add(e,t)}function n(){for(p=!0;h.size();){var e=h;h=i(),e.process()}p=!1}function o(e){p||(void 0===e&&(e=u),f&&(s(f),f=null),e?a():n())}function a(){f=l(n)}function s(e){var t=clearTimeout;return t(e)}function l(e){var t=function(e){return setTimeout(e,0)};return t(e)}e=e||{};var c=e.reporter,u=r.getOption(e,"async",!0),d=r.getOption(e,"auto",!0);d&&!u&&(c&&c.warn("Invalid options combination. auto=true and async=false is invalid. Setting async=true."),u=!0);var f,h=i(),p=!1;return{add:t,force:o}}},function(e,t){"use strict";function n(e,t,n){var i=e[t];return void 0!==i&&null!==i||void 0===n?i:n}var i=e.exports={};i.getOption=n},function(e,t,n){"use strict";var i=n(1);e.exports=function(e){function t(e,t){function n(){t(e)}if(!r(e))throw Error("Element is not detectable by this strategy.");if(i.isIE(8))l(e).object={proxy:n},e.attachEvent("onresize",n);else{var o=r(e);o.contentDocument.defaultView.addEventListener("resize",n)}}function n(e,t,n){function r(e,t){function n(){function n(){if("static"===c.position){e.style.position="relative";var t=function(e,t,n,i){function r(e){return e.replace(/[^-\d\.]/g,"")}var o=n[i];"auto"!==o&&"0"!==r(o)&&(e.warn("An element that is positioned static has style."+i+"="+o+" which is ignored due to the static positioning. The element will need to be positioned relative, so the style."+i+" will be set to 0. Element: ",t),t.style[i]=0)};t(a,e,c,"top"),t(a,e,c,"right"),t(a,e,c,"bottom"),t(a,e,c,"left")}}function s(){function i(e,t){return e.contentDocument?void t(e.contentDocument):void setTimeout(function(){i(e,t)},100)}o||n();var r=this;i(r,function(n){t(e)})}""!==c.position&&(n(c),o=!0);var u=document.createElement("object");u.style.cssText=r,u.type="text/html",u.onload=s,i.isIE()||(u.data="about:blank"),e.appendChild(u),l(e).object=u,i.isIE()&&(u.data="about:blank")}var r="display: block; position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: none; padding: 0; margin: 0; opacity: 0; z-index: -1000; pointer-events: none;",o=!1,c=window.getComputedStyle(e),u=e.offsetWidth,d=e.offsetHeight;l(e).startSize={width:u,height:d},s?s.add(n):n()}n||(n=t,t=e,e=null),e=e||{};i.isIE(8)?n(t):r(t,n)}function r(e){return l(e).object}function o(e){i.isIE(8)?e.detachEvent("onresize",l(e).object.proxy):e.removeChild(r(e)),delete l(e).object}e=e||{};var a=e.reporter,s=e.batchProcessor,l=e.stateHandler.getState;if(!a)throw Error("Missing required dependency: reporter.");return{makeDetectable:n,addListener:t,uninstall:o}}},function(e,t,n){"use strict";var i=n(2).forEach;e.exports=function(e){function t(){var e=500,t=500,n=document.createElement("div");n.style.cssText="position: absolute; width: "+2*e+"px; height: "+2*t+"px; visibility: hidden;";var i=document.createElement("div");i.style.cssText="position: absolute; width: "+e+"px; height: "+t+"px; overflow: scroll; visibility: none; top: "+3*-e+"px; left: "+3*-t+"px; visibility: hidden;",i.appendChild(n),document.body.insertBefore(i,document.body.firstChild);var r=e-i.clientWidth,o=t-i.clientHeight;return document.body.removeChild(i),{width:r,height:o}}function n(e,t){function n(t,n){n=n||function(e){document.head.appendChild(e)};var i=document.createElement("style");return i.innerHTML=t,i.id=e,n(i),i}if(!document.getElementById(e)){var i=t+"_animation",r=t+"_animation_active",o="/* Created by the element-resize-detector library. */\n";o+="."+t+" > div::-webkit-scrollbar { display: none; }\n\n",o+="."+r+" { -webkit-animation-duration: 0.1s; animation-duration: 0.1s; -webkit-animation-name: "+i+"; animation-name: "+i+"; }\n",o+="@-webkit-keyframes "+i+" { 0% { opacity: 1; } 50% { opacity: 0; } 100% { opacity: 1; } }\n",o+="@keyframes "+i+" { 0% { opacity: 1; } 50% { opacity: 0; } 100% { opacity: 1; } }",n(o)}}function r(e){e.className+=" "+p+"_animation_active"}function o(e,t){var n=u(e).listeners;if(!n.push)throw Error("Cannot add listener to an element that is not detectable.");u(e).listeners.push(t)}function a(e,t,n){function o(){if(e.debug){var n=Array.prototype.slice.call(arguments);if(n.unshift(d.get(t),"Scroll: "),l.log.apply)l.log.apply(null,n);else for(var i=0;n.length>i;i++)l.log(n[i])}}function a(e){function t(e){return e===e.ownerDocument.body||e.ownerDocument.body.contains(e)}return!t(e)}function s(e){var t=u(e).container.childNodes[0];return-1===getComputedStyle(t).width.indexOf("px")}function h(){var e=getComputedStyle(t),n={};return n.position=e.position,n.width=t.offsetWidth,n.height=t.offsetHeight,n.top=e.top,n.right=e.right,n.bottom=e.bottom,n.left=e.left,n.widthCSS=e.width,n.heightCSS=e.height,n}function v(){var e=h();u(t).startSize={width:e.width,height:e.height},o("Element start size",u(t).startSize)}function g(){u(t).listeners=[]}function m(){if(o("storeStyle invoked."),!u(t))return void o("Aborting because element has been uninstalled");var e=h();u(t).style=e}function y(e,t,n){u(e).lastWidth=t,u(e).lastHeight=n}function b(e){return u(e).container.childNodes[0].childNodes[0].childNodes[0]}function w(e){return b(e).childNodes[0]}function x(e){return u(e).container.childNodes[0].childNodes[0].childNodes[1]}function E(){return 2*f.width+1}function S(){return 2*f.height+1}function z(e){return e+10+E()}function T(e){return e+10+S()}function k(e){return 2*e+E()}function O(e){return 2*e+S()}function C(e,t,n){var i=b(e),r=x(e),o=z(t),a=T(n),s=k(t),l=O(n);i.scrollLeft=o,i.scrollTop=a,r.scrollLeft=s,r.scrollTop=l}function N(e,t,n){if(e.addEventListener)e.addEventListener(t,n);else{if(!e.attachEvent)return l.error("[scroll] Don't know how to add event listeners.");e.attachEvent("on"+t,n)}}function j(){var e=u(t).container;return e||(e=document.createElement("div"),e.className=p,e.style.cssText="visibility: hidden; display: inline; width: 0px; height: 0px; z-index: -1; overflow: hidden;",u(t).container=e,r(e),t.appendChild(e),N(e,"animationstart",function(){u(t).onRendered&&u(t).onRendered()})),e}function P(){function e(){var e=u(t).style;if("static"===e.position){t.style.position="relative";var n=function(e,t,n,i){function r(e){return e.replace(/[^-\d\.]/g,"")}var o=n[i];"auto"!==o&&"0"!==r(o)&&(e.warn("An element that is positioned static has style."+i+"="+o+" which is ignored due to the static positioning. The element will need to be positioned relative, so the style."+i+" will be set to 0. Element: ",t),t.style[i]=0)};n(l,t,e,"top"),n(l,t,e,"right"),n(l,t,e,"bottom"),n(l,t,e,"left")}}function n(e,t,n,i){return e=e?e+"px":"0",t=t?t+"px":"0",n=n?n+"px":"0",i=i?i+"px":"0","left: "+e+"; top: "+t+"; right: "+i+"; bottom: "+n+";"}if(o("Injecting elements"),!u(t))return void o("Aborting because element has been uninstalled");e();var i=u(t).container;i||(i=j());var r=f.width,a=f.height,s="position: absolute; overflow: hidden; z-index: -1; visibility: hidden; width: 100%; height: 100%; left: 0px; top: 0px;",c="position: absolute; overflow: hidden; z-index: -1; visibility: hidden; "+n(-(1+r),-(1+a),-a,-r),d="position: absolute; overflow: scroll; z-index: -1; visibility: hidden; width: 100%; height: 100%;",h="position: absolute; overflow: scroll; z-index: -1; visibility: hidden; width: 100%; height: 100%;",v="position: absolute; left: 0; top: 0;",g="position: absolute; width: 200%; height: 200%;",m=document.createElement("div"),y=document.createElement("div"),b=document.createElement("div"),w=document.createElement("div"),x=document.createElement("div"),E=document.createElement("div");m.style.cssText=s,m.className=p,y.className=p,y.style.cssText=c,b.style.cssText=d,w.style.cssText=v,x.style.cssText=h,E.style.cssText=g,b.appendChild(w),x.appendChild(E),y.appendChild(b),y.appendChild(x),m.appendChild(y),i.appendChild(m),N(b,"scroll",function(){u(t).onExpand&&u(t).onExpand()}),N(x,"scroll",function(){u(t).onShrink&&u(t).onShrink()})}function A(){function n(e,t,n){var i=w(e),r=z(t),o=T(n);i.style.width=r+"px",i.style.height=o+"px"}function r(i){var r=t.offsetWidth,a=t.offsetHeight;o("Storing current size",r,a),y(t,r,a),c.add(0,function(){if(e.debug){var i=t.offsetWidth,o=t.offsetHeight;i===r&&o===a||l.warn(d.get(t),"Scroll: Size changed before updating detector elements.")}n(t,r,a)}),c.add(1,function(){C(t,r,a)}),i&&c.add(2,i)}function a(){function e(){return void 0===u(t).lastNotifiedWidth}o("notifyListenersIfNeeded invoked");var n=u(t);return e()&&n.lastWidth===n.startSize.width&&n.lastHeight===n.startSize.height?o("Not notifying: Size is the same as the start size, and there has been no notification yet."):n.lastWidth===n.lastNotifiedWidth&&n.lastHeight===n.lastNotifiedHeight?o("Not notifying: Size already notified"):(o("Current size not notified, notifying..."),n.lastNotifiedWidth=n.lastWidth,n.lastNotifiedHeight=n.lastHeight,void i(u(t).listeners,function(e){e(t)}))}function f(){if(o("startanimation triggered."),s(t))return void o("Ignoring since element is still unrendered...");o("Element rendered.");var e=b(t),n=x(t);0!==e.scrollLeft&&0!==e.scrollTop&&0!==n.scrollLeft&&0!==n.scrollTop||(o("Scrollbars out of sync. Updating detector elements..."),r(a))}function h(){if(o("Scroll detected."),s(t))return void o("Scroll event fired while unrendered. Ignoring...");var e=t.offsetWidth,n=t.offsetHeight;e!==t.lastWidth||n!==t.lastHeight?(o("Element size changed."),r(a)):o("Element size has not changed ("+e+"x"+n+").")}if(o("registerListenersAndPositionElements invoked."),!u(t))return void o("Aborting because element has been uninstalled");u(t).onRendered=f,u(t).onExpand=h,u(t).onShrink=h;var p=u(t).style;n(t,p.width,p.height)}function H(){if(o("finalizeDomMutation invoked."),!u(t))return void o("Aborting because element has been uninstalled");var e=u(t).style;y(t,e.width,e.height),C(t,e.width,e.height)}function M(){n(t)}function _(){o("Installing..."),g(),v(),c.add(0,m),c.add(1,P),c.add(2,A),c.add(3,H),c.add(4,M)}n||(n=t,t=e,e=null),e=e||{},o("Making detectable..."),a(t)?(o("Element is detached"),j(),o("Waiting until element is attached..."),u(t).onRendered=function(){o("Element is now attached"),_()}):_()}function s(e){var t=u(e);t.busy||e.removeChild(t.container)}e=e||{};var l=e.reporter,c=e.batchProcessor,u=e.stateHandler.getState,d=e.idHandler;if(!c)throw Error("Missing required dependency: batchProcessor");if(!l)throw Error("Missing required dependency: reporter.");var f=t(),h="erd_scroll_detection_scrollbar_style",p="erd_scroll_detection_container";return n(h,p),{makeDetectable:a,addListener:o,uninstall:s}}},function(e,t,n){"use strict";function i(e,t,n){var i=e[t];return void 0!==i&&null!==i||void 0===n?i:n}var r=n(2).forEach,o=n(11),a=n(14),s=n(12),l=n(13),c=n(15),u=n(1),d=n(6),f=n(16),h=n(8),p=n(9);e.exports=function(e){function t(e,t,n){function o(e){var t=S.get(e);r(t,function(t){t(e)})}function a(e,t,n){S.add(t,n),e&&n(t)}function s(e){return Array.isArray(e)||void 0!==e.length}function l(e){if(Array.isArray(e))return e;var n=[];return r(t,function(e){n.push(e)}),n}function c(e){return e&&1===e.nodeType}if(n||(n=t,t=e,e={}),!t)throw Error("At least one element required.");if(!n)throw Error("Listener required.");if(c(t))t=[t];else{if(!s(t))return y.error("Invalid arguments. Must be a DOM element or a collection of DOM elements.");t=l(t)}var u=0,d=i(e,"callOnAdd",x.callOnAdd),h=i(e,"onReady",function(){}),p=i(e,"debug",x.debug);r(t,function(e){f.getState(e)||(f.initState(e),v.set(e));var i=v.get(e);return p&&y.log("Attaching listener to element",i,e),z.isDetectable(e)?(p&&y.log(i,"Already detecable, adding listener."),a(d,e,n),void u++):(p&&y.log(i,"Not detectable."),z.isBusy(e)?(p&&y.log(i,"System busy making it detectable"),a(d,e,n),O[i]=O[i]||[],void O[i].push(function(){u++,u===t.length&&h()})):(p&&y.log(i,"Making detectable..."),z.markBusy(e,!0),E.makeDetectable({debug:p},e,function(e){if(p&&y.log(i,"onElementDetectable"),f.getState(e)){if(z.markAsDetectable(e),z.markBusy(e,!1),E.addListener(e,o),a(d,e,n),f.getState(e).startSize){var s=e.offsetWidth,l=e.offsetHeight;f.getState(e).startSize.width===s&&f.getState(e).startSize.height===l||o(e)}O[i]&&r(O[i],function(e){e()})}else p&&y.log(i,"Element uninstalled before being detectable.");delete O[i],u++,u===t.length&&h()})))}),u===t.length&&h()}function n(e){S.removeAllListeners(e),E.uninstall(e),f.cleanState(e)}e=e||{};var v;if(e.idHandler)v={get:function(t){e.idHandler.get(t,!0)},set:e.idHandler.set};else{var g=s(),m=l({idGenerator:g,stateHandler:f});v=m}var y=e.reporter;if(!y){var b=y===!1;y=c(b)}var w=i(e,"batchProcessor",d({reporter:y})),x={};x.callOnAdd=!!i(e,"callOnAdd",!0),x.debug=!!i(e,"debug",!1);var E,S=a(v),z=o({stateHandler:f}),T=i(e,"strategy","object"),k={reporter:y,batchProcessor:w,stateHandler:f,idHandler:v};if("scroll"===T&&(u.isLegacyOpera()?(y.warn("Scroll strategy is not supported on legacy Opera. Changing to object strategy."),T="object"):u.isIE(9)&&(y.warn("Scroll strategy is not supported on IE9. Changing to object strategy."),T="object")),"scroll"===T)E=p(k);else{if("object"!==T)throw Error("Invalid strategy name: "+T);E=h(k)}var O={};return{listenTo:t,removeListener:S.removeListener,removeAllListeners:S.removeAllListeners,uninstall:n}}},function(e,t){"use strict";e.exports=function(e){function t(e){var t=o(e);return t&&!!t.isDetectable}function n(e){o(e).isDetectable=!0}function i(e){return!!o(e).busy}function r(e,t){o(e).busy=!!t}var o=e.stateHandler.getState;return{isDetectable:t,markAsDetectable:n,isBusy:i,markBusy:r}}},function(e,t){"use strict";e.exports=function(){function e(){return t++}var t=1;return{generate:e}}},function(e,t){"use strict";e.exports=function(e){function t(e){var t=r(e);return t&&void 0!==t.id?t.id:null}function n(e){var t=r(e);if(!t)throw Error("setId required the element to have a resize detection state.");var n=i.generate();return t.id=n,n}var i=e.idGenerator,r=e.stateHandler.getState;return{get:t,set:n}}},function(e,t){"use strict";e.exports=function(e){function t(t){return o[e.get(t)]||[]}function n(t,n){var i=e.get(t);o[i]||(o[i]=[]),o[i].push(n)}function i(e,n){for(var i=t(e),r=0,o=i.length;o>r;++r)if(i[r]===n){i.splice(r,1);break}}function r(t){var n=o[e.get(t)];n&&(n.length=0)}var o={};return{get:t,add:n,removeListener:i,removeAllListeners:r}}},function(e,t){"use strict";e.exports=function(e){function t(){}var n={log:t,warn:t,error:t};if(!e&&window.console){var i=function(e,t){e[t]=function(){var e=console[t];if(e.apply)e.apply(console,arguments);else for(var n=0;arguments.length>n;n++)e(arguments[n])}};i(n,"log"),i(n,"warn"),i(n,"error")}return n}},function(e,t){"use strict";function n(e){return e[o]={},i(e)}function i(e){return e[o]}function r(e){delete e[o]}var o="_erd";e.exports={initState:n,getState:i,cleanState:r}},function(e,t,n){"use strict";var i=function(e,t,n,i,r,o,a,s){if(!e){var l;if(void 0===t)l=Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var c=[n,i,r,o,a,s],u=0;l=Error(t.replace(/%s/g,function(){return c[u++]})),l.name="Invariant Violation"}throw l.framesToPop=1,l}};e.exports=i},function(e,t,n){function i(e,t,n){function i(t){var n=y,i=b;return y=b=void 0,z=t,x=e.apply(i,n)}function u(e){return z=e,E=setTimeout(h,t),T?i(e):x}function d(e){var n=e-S,i=e-z,r=t-n;return k?c(r,w-i):r}function f(e){var n=e-S,i=e-z;return!S||n>=t||0>n||k&&i>=w}function h(){var e=o();return f(e)?p(e):void(E=setTimeout(h,d(e)))}function p(e){return clearTimeout(E),E=void 0,O&&y?i(e):(y=b=void 0,x)}function v(){void 0!==E&&clearTimeout(E),S=z=0,y=b=E=void 0}function g(){return void 0===E?x:p(o())}function m(){var e=o(),n=f(e);if(y=arguments,b=this,S=e,n){if(void 0===E)return u(S);if(k)return clearTimeout(E),E=setTimeout(h,t),i(S)}return void 0===E&&(E=setTimeout(h,t)),x}var y,b,w,x,E,S=0,z=0,T=!1,k=!1,O=!0;if("function"!=typeof e)throw new TypeError(s);return t=a(t)||0,r(n)&&(T=!!n.leading,k="maxWait"in n,w=k?l(a(n.maxWait)||0,t):w,O="trailing"in n?!!n.trailing:O),m.cancel=v,m.flush=g,m}var r=n(3),o=n(19),a=n(21),s="Expected a function",l=Math.max,c=Math.min;e.exports=i},function(e,t){var n=Date.now;e.exports=n},function(e,t,n){function i(e,t,n){var i=!0,s=!0;if("function"!=typeof e)throw new TypeError(a);return o(n)&&(i="leading"in n?!!n.leading:i,s="trailing"in n?!!n.trailing:s),r(e,t,{leading:i,maxWait:t,trailing:s})}var r=n(18),o=n(3),a="Expected a function";e.exports=i},function(e,t){function n(e){return e}e.exports=n},function(t,n){t.exports=e},function(e,n){e.exports=t}])}); \ No newline at end of file diff --git a/src/SizeMe.js b/src/SizeMe.js index ccacf5a..cf5be2b 100644 --- a/src/SizeMe.js +++ b/src/SizeMe.js @@ -64,10 +64,18 @@ Placeholder.propTypes = { * It took me forever to figure this out, so tread extra careful on this one! */ const RenderWrapper = (WrappedComponent) => { - function SizeMeRenderer({ explicitRef, className, style, size, ...restProps }) { + function SizeMeRenderer(props) { + const { + explicitRef, + className, + style, + size, + disablePlaceholder, + ...restProps + } = props; const { width, height } = size; - const toRender = (width === undefined && height === undefined) + const toRender = (width === undefined && height === undefined && !disablePlaceholder) ? : ; @@ -87,7 +95,8 @@ const RenderWrapper = (WrappedComponent) => { size: PropTypes.shape({ width: PropTypes.number, height: PropTypes.number - }) + }), + disablePlaceholder: PropTypes.bool }; return SizeMeRenderer; @@ -206,6 +215,7 @@ function SizeMe(config = defaultConfig) { ); @@ -216,4 +226,14 @@ function SizeMe(config = defaultConfig) { }; } +/** + * Allow SizeMe to run within SSR environments. This is a "global" behaviour + * flag that should be set within the initialisation phase of your application. + * + * Warning: don't set this flag unless you need to as using it may cause + * extra render cycles to happen within your components depending on the logic + * contained within them around the usage of the `size` data. + */ +SizeMe.enableSSRBehaviour = false; + export default SizeMe; diff --git a/test/SizeMe.test.js b/test/SizeMe.test.js index f4d9063..d1612dd 100644 --- a/test/SizeMe.test.js +++ b/test/SizeMe.test.js @@ -4,7 +4,8 @@ import React from 'react'; import { expect } from 'chai'; import { describeWithDOM } from './jsdom'; import sinon from 'sinon'; -import { mount } from 'enzyme'; +import { mount, shallow } from 'enzyme'; +import { renderToString } from 'react-dom/server' const html = ` @@ -25,6 +26,7 @@ const html = ` describeWithDOM(`Given the SizeMe library`, () => { let SizeMe; + let SizeMeRewireAPI; let resizeDetectorMock; const placeholderHtml = `

`; @@ -32,7 +34,7 @@ describeWithDOM(`Given the SizeMe library`, () => { SizeMe = require(`../src/index.js`).default; // Set up our mocks. - const SizeMeRewireAPI = SizeMe.__RewireAPI__; + SizeMeRewireAPI = SizeMe.__RewireAPI__; resizeDetectorMock = { // :: domEl -> void @@ -65,199 +67,215 @@ describeWithDOM(`Given the SizeMe library`, () => { }); }); - describe(`And the resize detector`, () => { - describe(`When mounting and unmounting the placeholder component`, () => { - it(`Then the resizeDetector registration and deregistration should be called`, () => { - const SizeAwareComponent = SizeMe()(() =>
); + describe(`When mounting and unmounting the placeholder component`, () => { + it(`Then the resizeDetector registration and deregistration should be called`, () => { + const SizeAwareComponent = SizeMe()(() =>
); - const mounted = mount(); + const mounted = mount(); - expect(resizeDetectorMock.listenTo.callCount).to.equal(1); - expect(resizeDetectorMock.removeAllListeners.callCount).to.equal(0); + expect(resizeDetectorMock.listenTo.callCount).to.equal(1); + expect(resizeDetectorMock.removeAllListeners.callCount).to.equal(0); - mounted.unmount(); + mounted.unmount(); - expect(resizeDetectorMock.listenTo.callCount).to.equal(1); - expect(resizeDetectorMock.removeAllListeners.callCount).to.equal(1); - }); + expect(resizeDetectorMock.listenTo.callCount).to.equal(1); + expect(resizeDetectorMock.removeAllListeners.callCount).to.equal(1); }); + }); - describe(`When mounting and unmounting a size aware component`, () => { - it(`Then the resizeDetector registration and deregistration should be called`, () => { - const SizeAwareComponent = SizeMe({ monitorHeight: true })( - ({ size: { width, height } }) =>
{width} x {height}
- ); - - const mounted = mount(); - - // An add listener should have been called for the placeholder. - expect(resizeDetectorMock.listenTo.callCount).to.equal(1); - expect(resizeDetectorMock.removeAllListeners.callCount).to.equal(0); - - // Get the callback for size changes. - const checkIfSizeChangedCallback = resizeDetectorMock.listenTo.args[0][1]; - checkIfSizeChangedCallback({ - getBoundingClientRect: () => ({ - width: 100, - height: 100 - }) - }); - - // Our actual component should have mounted, therefore a removelistener - // should have been called on the placeholder, and an add listener - // on the newly mounted component. - expect(mounted.text()).to.equal(`100 x 100`); - expect(resizeDetectorMock.listenTo.callCount).to.equal(2); - expect(resizeDetectorMock.removeAllListeners.callCount).to.equal(1); - - // umount - mounted.unmount(); - - // The remove listener should have been called! - expect(resizeDetectorMock.listenTo.callCount).to.equal(2); - expect(resizeDetectorMock.removeAllListeners.callCount).to.equal(2); + describe(`When the wrapped component gets mounted after the placeholder`, () => { + it(`Then the resizeDetector registration and deregistration should be called`, () => { + const SizeAwareComponent = SizeMe({ monitorHeight: true })( + ({ size: { width, height } }) =>
{width} x {height}
+ ); + + const mounted = mount(); + + // An add listener should have been called for the placeholder. + expect(resizeDetectorMock.listenTo.callCount).to.equal(1); + expect(resizeDetectorMock.removeAllListeners.callCount).to.equal(0); + + // Get the callback for size changes. + const checkIfSizeChangedCallback = resizeDetectorMock.listenTo.args[0][1]; + checkIfSizeChangedCallback({ + getBoundingClientRect: () => ({ + width: 100, + height: 100 + }) }); + + // Our actual component should have mounted, therefore a removelistener + // should have been called on the placeholder, and an add listener + // on the newly mounted component. + expect(mounted.text()).to.equal(`100 x 100`); + expect(resizeDetectorMock.listenTo.callCount).to.equal(2); + expect(resizeDetectorMock.removeAllListeners.callCount).to.equal(1); + + // umount + mounted.unmount(); + + // The remove listener should have been called! + expect(resizeDetectorMock.listenTo.callCount).to.equal(2); + expect(resizeDetectorMock.removeAllListeners.callCount).to.equal(2); }); }); - describe(`When rendering a size aware component`, () => { - describe(`And no className or style has been provided`, () => { - it(`Then it should render the default placeholder`, () => { - const SizeAwareComponent = SizeMe()(() =>
); + describe(`When no className or style has been provided`, () => { + it(`Then it should render the default placeholder`, () => { + const SizeAwareComponent = SizeMe()(() =>
); - const mounted = mount(); + const mounted = mount(); - expect(mounted.html()) - .to.equal(placeholderHtml); - }); + expect(mounted.html()) + .to.equal(placeholderHtml); }); + }); - describe(`And only a className has been provided`, () => { - it(`Then it should render a placeholder with the className`, () => { - const SizeAwareComponent = SizeMe()(() =>
); + describe(`When only a className has been provided`, () => { + it(`Then it should render a placeholder with the className`, () => { + const SizeAwareComponent = SizeMe()(() =>
); - const mounted = mount(); + const mounted = mount(); - expect(mounted.html()) - .to.equal(`
`); - }); + expect(mounted.html()) + .to.equal(`
`); }); + }); - describe(`And only a style has been provided`, () => { - it(`Then it should render a placeholder with the style`, () => { - const SizeAwareComponent = SizeMe()(() =>
); + describe(`When only a style has been provided`, () => { + it(`Then it should render a placeholder with the style`, () => { + const SizeAwareComponent = SizeMe()(() =>
); - const mounted = mount(); + const mounted = mount(); - expect(mounted.html()) - .to.equal(`
`); - }); + expect(mounted.html()) + .to.equal(`
`); }); + }); - describe(`And a className and style have been provided`, () => { - it(`Then it should render a placeholder with both`, () => { - const SizeAwareComponent = SizeMe()(() =>
); + describe(`When a className and style have been provided`, () => { + it(`Then it should render a placeholder with both`, () => { + const SizeAwareComponent = SizeMe()(() =>
); - const mounted = mount( - - ); + const mounted = mount( + + ); - expect(mounted.html()) - .to.equal(`
`); - }); + expect(mounted.html()) + .to.equal(`
`); }); + }); - describe(`And the size event has occurred when only width is being monitored`, () => { - it(`Then expected sizes should be provided to the rendered component`, () => { - const SizeAwareComponent = SizeMe({ monitorWidth: true, monitorHeight: false })( - ({ size: { width, height } }) =>
{width} x {height || `null`}
- ); - - const mounted = mount(); + describe(`When the size event has occurred when only width is being monitored`, () => { + it(`Then expected sizes should be provided to the rendered component`, () => { + const SizeAwareComponent = SizeMe({ monitorWidth: true, monitorHeight: false })( + ({ size: { width, height } }) =>
{width} x {height || `null`}
+ ); - // Initial render should be as expected. - expect(mounted.html()).to.equal(placeholderHtml); + const mounted = mount(); - // Get the callback for size changes. - const checkIfSizeChangedCallback = resizeDetectorMock.listenTo.args[0][1]; - checkIfSizeChangedCallback({ - getBoundingClientRect: () => ({ width: 100, height: 150 }) - }); + // Initial render should be as expected. + expect(mounted.html()).to.equal(placeholderHtml); - // Update should have occurred immediately. - expect(mounted.text()).to.equal(`100 x null`); + // Get the callback for size changes. + const checkIfSizeChangedCallback = resizeDetectorMock.listenTo.args[0][1]; + checkIfSizeChangedCallback({ + getBoundingClientRect: () => ({ width: 100, height: 150 }) }); - }); - describe(`And the size event has occurred when only height is being monitored`, () => { - it(`Then expected sizes should be provided to the rendered component`, () => { - const SizeAwareComponent = SizeMe({ monitorWidth: false, monitorHeight: true })( - ({ size: { width, height } }) =>
{width || `null`} x {height}
- ); + // Update should have occurred immediately. + expect(mounted.text()).to.equal(`100 x null`); + }); + }); - const mounted = mount(); + describe(`When the size event has occurred when only height is being monitored`, () => { + it(`Then expected sizes should be provided to the rendered component`, () => { + const SizeAwareComponent = SizeMe({ monitorWidth: false, monitorHeight: true })( + ({ size: { width, height } }) =>
{width || `null`} x {height}
+ ); - // Initial render should be as expected. - expect(mounted.html()).to.equal(placeholderHtml); + const mounted = mount(); - // Get the callback for size changes. - const checkIfSizeChangedCallback = resizeDetectorMock.listenTo.args[0][1]; - checkIfSizeChangedCallback({ - getBoundingClientRect: () => ({ width: 100, height: 150 }) - }); + // Initial render should be as expected. + expect(mounted.html()).to.equal(placeholderHtml); - // Update should have occurred immediately. - expect(mounted.text()).to.equal(`null x 150`); + // Get the callback for size changes. + const checkIfSizeChangedCallback = resizeDetectorMock.listenTo.args[0][1]; + checkIfSizeChangedCallback({ + getBoundingClientRect: () => ({ width: 100, height: 150 }) }); - }); - describe(`And the size event has occurred when width and height are being monitored`, () => { - it(`Then expected sizes should be provided to the rendered component`, () => { - const SizeAwareComponent = SizeMe({ monitorWidth: true, monitorHeight: true })( - ({ size: { width, height } }) =>
{width} x {height}
- ); + // Update should have occurred immediately. + expect(mounted.text()).to.equal(`null x 150`); + }); + }); - const mounted = mount(); + describe(`When the size event has occurred when width and height are being monitored`, () => { + it(`Then expected sizes should be provided to the rendered component`, () => { + const SizeAwareComponent = SizeMe({ monitorWidth: true, monitorHeight: true })( + ({ size: { width, height } }) =>
{width} x {height}
+ ); - // Initial render should be as expected. - expect(mounted.html()).to.equal(placeholderHtml); + const mounted = mount(); - // Get the callback for size changes. - const checkIfSizeChangedCallback = resizeDetectorMock.listenTo.args[0][1]; - checkIfSizeChangedCallback({ - getBoundingClientRect: () => ({ width: 100, height: 150 }) - }); + // Initial render should be as expected. + expect(mounted.html()).to.equal(placeholderHtml); - // Update should have occurred immediately. - expect(mounted.text()).to.equal(`100 x 150`); + // Get the callback for size changes. + const checkIfSizeChangedCallback = resizeDetectorMock.listenTo.args[0][1]; + checkIfSizeChangedCallback({ + getBoundingClientRect: () => ({ width: 100, height: 150 }) }); + + // Update should have occurred immediately. + expect(mounted.text()).to.equal(`100 x 150`); }); + }); - describe(`And it receives new non-size props`, () => { - it(`Then the new props should be passed into the component`, () => { - const SizeAwareComponent = SizeMe({ monitorHeight: true, monitorWidth: true })( - function ({ size: { width, height }, otherProp }) { - return
{width} x {height} & {otherProp}
; - } - ); + describe(`When it receives new non-size props`, () => { + it(`Then the new props should be passed into the component`, () => { + const SizeAwareComponent = SizeMe({ monitorHeight: true, monitorWidth: true })( + function ({ size: { width, height }, otherProp }) { + return
{width} x {height} & {otherProp}
; + } + ); - const mounted = mount(); + const mounted = mount(); - // Get the callback for size changes. - const checkIfSizeChangedCallback = resizeDetectorMock.listenTo.args[0][1]; - checkIfSizeChangedCallback({ - getBoundingClientRect: () => ({ width: 100, height: 100 }) - }); + // Get the callback for size changes. + const checkIfSizeChangedCallback = resizeDetectorMock.listenTo.args[0][1]; + checkIfSizeChangedCallback({ + getBoundingClientRect: () => ({ width: 100, height: 100 }) + }); - // Output should contain foo. - expect(mounted.text()).to.equal(`100 x 100 & foo`); + // Output should contain foo. + expect(mounted.text()).to.equal(`100 x 100 & foo`); - // Update the other prop. - mounted.setProps({ otherProp: `bar` }); + // Update the other prop. + mounted.setProps({ otherProp: `bar` }); - // Output should contain foo. - expect(mounted.text()).to.equal(`100 x 100 & bar`); - }); + // Output should contain foo. + expect(mounted.text()).to.equal(`100 x 100 & bar`); + }); + }); + + describe(`When running is SSR mode`, () => { + beforeEach(() => { + SizeMe.enableSSRBehaviour = true; + }); + + it(`Then it should render the wrapped rather than the placeholder`, () => { + const SizeAwareComponent = SizeMe({ monitorHeight: true, monitorWidth: true })( + function ({ size: { width, height } }) { + return
{width || `undefined`} x {height || `undefined`}
; + } + ); + + const mounted = renderToString() + .replace(//g, ``); + + // Output should contain undefined for width and height. + expect(mounted).contains(`undefined x undefined`); }); }); }, html);