├── .eslintignore ├── .eslintrc.yml ├── .gitignore ├── README.md ├── docs ├── 1.js ├── index.html └── main.js ├── package-lock.json ├── package.json ├── src ├── api.js ├── components │ ├── App.css │ ├── App.js │ ├── Icon.js │ ├── IndexPage.css │ ├── IndexPage.js │ ├── MoviePage.css │ ├── MoviePage.js │ ├── Spinner.css │ └── Spinner.js ├── index.css ├── index.html └── index.js └── webpack.config.js /.eslintignore: -------------------------------------------------------------------------------- 1 | /dist/ 2 | /react-modules/ 3 | /docs/ 4 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | parser: babel-eslint 2 | 3 | extends: 4 | - eslint:recommended 5 | - plugin:react/recommended 6 | 7 | rules: 8 | strict: off 9 | react/prop-types: off 10 | 11 | settings: 12 | react: 13 | version: "15.0" 14 | 15 | env: 16 | es6: true 17 | browser: true 18 | 19 | settings: 20 | react: 21 | version: detect 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /dist/ 2 | /node_modules/ 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Suspense demo 2 | 3 | This is an implementation of the demo shown by Gaearon in his [talk at JSConf 4 | Iceland](https://www.youtube.com/watch?v=v6iR3Zk4oDY). It uses *unstable* features available in 5 | the current React release. 6 | 7 | You can try the demo [here](http://benoitzugmeyer.github.io/react-suspense-demo/). 8 | -------------------------------------------------------------------------------- /docs/1.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[1],{25:function(e,t,n){var a=n(26);"string"==typeof a&&(a=[[e.i,a,""]]);var r={hmr:!0,transform:void 0,insertInto:void 0};n(2)(a,r);a.locals&&(e.exports=a.locals)},26:function(e,t,n){(e.exports=n(1)(!1)).push([e.i,".MovieDetails {\n display: flex;\n margin-bottom: var(--gutter);\n align-items: flex-start;\n}\n.MovieDetails h1,\n.MovieDetails .ratings {\n border-bottom: 2px solid #111629;\n margin: 0 0 var(--gutter);\n padding-bottom: var(--gutter);\n}\n.MovieDetails .poster {\n margin-right: var(--gutter);\n}\n.MovieDetails .poster img {\n width: 100%;\n}\n.MovieDetails .details {\n flex: 1;\n}\n.MovieDetails .ratings {\n display: flex;\n}\n\n.Rating {\n flex: 1;\n text-align: center;\n}\n\n.Rating:not(:last-child) {\n margin-right: var(--gutter);\n}\n\n.Rating .rating-score {\n margin-top: var(--small-gutter);\n font-size: 18px;\n font-weight: bold;\n}\n\n.MovieReviews {\n display: flex;\n flex-wrap: wrap;\n margin: calc(var(--gutter) / -2);\n align-items: flex-start;\n}\n\n.MovieReview {\n flex: 1;\n min-width: 200px;\n margin: calc(var(--gutter) / 2);\n}\n\n.MovieReview .sub-text {\n margin-top: var(--small-gutter);\n}\n",""])},27:function(e,t,n){"use strict";n.r(t),n.d(t,"default",function(){return b});var a=n(0),r=n.n(a),i=n(6),l=n(7),s=n(8),c=n(3);n(25);function o(){return(o=Object.assign||function(e){for(var t=1;tr.a.createElement(d,o({key:e.id},e))))}const p=Object(i.unstable_createResource)(e=>new Promise((t,n)=>{const a=new Image;a.onload=()=>t(e),a.onerror=n,a.src=e}));function f(e){return r.a.createElement("img",o({},e,{src:p.read(e.src)}))}function E({movieId:e}){const{ratingSummary:t,ratings:n,title:a,posters:i}=m.read(e);return r.a.createElement("div",{className:"MovieDetails"},r.a.createElement("div",{className:"poster"},r.a.createElement(f,{src:i.detailed,alt:"poster"})),r.a.createElement("div",{className:"details"},r.a.createElement("h1",null,a),r.a.createElement("div",{className:"ratings"},r.a.createElement(v,{label:"Tomatometer",score:n.critics_score,icon:n.critics_rating}),r.a.createElement(v,{label:"Audience",score:n.audience_score,icon:n.audience_rating})),r.a.createElement("div",{className:"critic"},r.a.createElement("div",{className:"small-title"},"Critics consensus"),t.consensus)))}function b({movieId:e}){return r.a.createElement(r.a.Fragment,null,r.a.createElement(E,{movieId:e}),r.a.createElement(a.Suspense,{maxDuration:500,fallback:r.a.createElement(c.a,null)},r.a.createElement(g,{movieId:e})))}}}]); -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | React Suspense Demo 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /docs/main.js: -------------------------------------------------------------------------------- 1 | !function(e){function t(t){for(var n,o,i=t[0],l=t[1],a=0,c=[];a=0&&s.splice(t,1)}function v(e){var t=document.createElement("style");if(void 0===e.attrs.type&&(e.attrs.type="text/css"),void 0===e.attrs.nonce){var r=function(){0;return n.nc}();r&&(e.attrs.nonce=r)}return y(t,e.attrs),m(e,t),t}function y(e,t){Object.keys(t).forEach(function(n){e.setAttribute(n,t[n])})}function g(e,t){var n,r,o,i;if(t.transform&&e.css){if(!(i="function"==typeof t.transform?t.transform(e.css):t.transform.default(e.css)))return function(){};e.css=i}if(t.singleton){var l=c++;n=u||(u=v(t)),r=x.bind(null,n,l,!1),o=x.bind(null,n,l,!0)}else e.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(n=function(e){var t=document.createElement("link");return void 0===e.attrs.type&&(e.attrs.type="text/css"),e.attrs.rel="stylesheet",y(t,e.attrs),m(e,t),t}(t),r=function(e,t,n){var r=n.css,o=n.sourceMap,i=void 0===t.convertToAbsoluteUrls&&o;(t.convertToAbsoluteUrls||i)&&(r=f(r));o&&(r+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(o))))+" */");var l=new Blob([r],{type:"text/css"}),a=e.href;e.href=URL.createObjectURL(l),a&&URL.revokeObjectURL(a)}.bind(null,n,t),o=function(){h(n),n.href&&URL.revokeObjectURL(n.href)}):(n=v(t),r=function(e,t){var n=t.css,r=t.media;r&&e.setAttribute("media",r);if(e.styleSheet)e.styleSheet.cssText=n;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(n))}}.bind(null,n),o=function(){h(n)});return r(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;r(e=t)}else o()}}e.exports=function(e,t){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");(t=t||{}).attrs="object"==typeof t.attrs?t.attrs:{},t.singleton||"boolean"==typeof t.singleton||(t.singleton=l()),t.insertInto||(t.insertInto="head"),t.insertAt||(t.insertAt="bottom");var n=p(e,t);return d(n,t),function(e){for(var r=[],o=0;osetTimeout(e,3e3)),t.reviews.reviews}},function(e,t,n){"use strict";n.d(t,"a",function(){return c});var r=n(0),o=n.n(r);const i="https://staticv2-4.rottentomatoes.com/static/images";function l(e){return{background:`transparent url(${i}/redesign/icons-v2.png) no-repeat`,backgroundPosition:e}}function a(e){return{background:`transparent url(${i}/icons/${e}) no-repeat`,backgroundSize:"cover"}}const u={tiny:{size:16,styles:{certified:a("CF_16x16.png"),fresh:a("fresh-16.png"),upright:a("popcorn-16.png"),rotten:a("splat-16.png"),spilled:a("badpopcorn-16.png"),wts:a("wts-16.png")}},big:{size:48,styles:{certified:l("-192px -96px"),fresh:l("-192px -48px"),upright:l("-240px -48px"),rotten:l("-240px -96px"),spilled:l("-192px 0"),wts:l("-240px 0")}},medium:{size:32,styles:{certified:a("CF-32.png"),fresh:l("-64px -128px"),upright:l("-32px -128px"),rotten:l("-96px -128px"),spilled:l("-128px -128px"),wts:l("0px -128px")}},small:{size:24,styles:{certified:a("CF-24.png"),fresh:l("-288px -48px"),upright:l("-288px -24px"),rotten:l("-288px -96px"),spilled:l("-288px -120px"),wts:l("-288px 0px")}}};function c({type:e,size:t="small"}){if(!u.hasOwnProperty(t))throw new Error(`Invalid icon size "${t}"`);"certifiedfresh"===(e=e.toLowerCase().replace(/[^a-z]+/g,""))&&(e="certified"),"popcorn"===e&&(e="upright"),"anticipated"===e&&(e="wts");const{styles:n,size:r}=u[t];if(!n.hasOwnProperty(e))throw new Error(`Invalid icon type "${e}"`);return o.a.createElement("div",{style:Object.assign({width:r,height:r,display:"inline-block",verticalAlign:"middle"},n[e])})}},function(e,t,n){"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(e){console.error(e)}}(),e.exports=n(11)},function(e,t,n){"use strict"; 7 | /** @license React v16.7.0 8 | * react.production.min.js 9 | * 10 | * Copyright (c) Facebook, Inc. and its affiliates. 11 | * 12 | * This source code is licensed under the MIT license found in the 13 | * LICENSE file in the root directory of this source tree. 14 | */var r=n(4),o="function"==typeof Symbol&&Symbol.for,i=o?Symbol.for("react.element"):60103,l=o?Symbol.for("react.portal"):60106,a=o?Symbol.for("react.fragment"):60107,u=o?Symbol.for("react.strict_mode"):60108,c=o?Symbol.for("react.profiler"):60114,s=o?Symbol.for("react.provider"):60109,f=o?Symbol.for("react.context"):60110,d=o?Symbol.for("react.concurrent_mode"):60111,p=o?Symbol.for("react.forward_ref"):60112,m=o?Symbol.for("react.suspense"):60113,h=o?Symbol.for("react.memo"):60115,v=o?Symbol.for("react.lazy"):60116,y="function"==typeof Symbol&&Symbol.iterator;function g(e){for(var t=arguments.length-1,n="https://reactjs.org/docs/error-decoder.html?invariant="+e,r=0;rM.length&&M.push(e)}function D(e,t,n){return null==e?0:function e(t,n,r,o){var a=typeof t;"undefined"!==a&&"boolean"!==a||(t=null);var u=!1;if(null===t)u=!0;else switch(a){case"string":case"number":u=!0;break;case"object":switch(t.$$typeof){case i:case l:u=!0}}if(u)return r(o,t,""===n?"."+R(t,0):n),1;if(u=0,n=""===n?".":n+":",Array.isArray(t))for(var c=0;cthis.eventPool.length&&this.eventPool.push(e)}function fe(e){e.eventPool=[],e.getPooled=ce,e.release=se}o(ue.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=le)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=le)},persist:function(){this.isPersistent=le},isPersistent:ae,destructor:function(){var e,t=this.constructor.Interface;for(e in t)this[e]=null;this.nativeEvent=this._targetInst=this.dispatchConfig=null,this.isPropagationStopped=this.isDefaultPrevented=ae,this._dispatchInstances=this._dispatchListeners=null}}),ue.Interface={type:null,target:null,currentTarget:function(){return null},eventPhase:null,bubbles:null,cancelable:null,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:null,isTrusted:null},ue.extend=function(e){function t(){}function n(){return r.apply(this,arguments)}var r=this;t.prototype=r.prototype;var i=new t;return o(i,n.prototype),n.prototype=i,n.prototype.constructor=n,n.Interface=o({},r.Interface,e),n.extend=r.extend,fe(n),n},fe(ue);var de=ue.extend({data:null}),pe=ue.extend({data:null}),me=[9,13,27,32],he=H&&"CompositionEvent"in window,ve=null;H&&"documentMode"in document&&(ve=document.documentMode);var ye=H&&"TextEvent"in window&&!ve,ge=H&&(!he||ve&&8=ve),be=String.fromCharCode(32),we={beforeInput:{phasedRegistrationNames:{bubbled:"onBeforeInput",captured:"onBeforeInputCapture"},dependencies:["compositionend","keypress","textInput","paste"]},compositionEnd:{phasedRegistrationNames:{bubbled:"onCompositionEnd",captured:"onCompositionEndCapture"},dependencies:"blur compositionend keydown keypress keyup mousedown".split(" ")},compositionStart:{phasedRegistrationNames:{bubbled:"onCompositionStart",captured:"onCompositionStartCapture"},dependencies:"blur compositionstart keydown keypress keyup mousedown".split(" ")},compositionUpdate:{phasedRegistrationNames:{bubbled:"onCompositionUpdate",captured:"onCompositionUpdateCapture"},dependencies:"blur compositionupdate keydown keypress keyup mousedown".split(" ")}},xe=!1;function ke(e,t){switch(e){case"keyup":return-1!==me.indexOf(t.keyCode);case"keydown":return 229!==t.keyCode;case"keypress":case"mousedown":case"blur":return!0;default:return!1}}function Te(e){return"object"==typeof(e=e.detail)&&"data"in e?e.data:null}var Ee=!1;var Ce={eventTypes:we,extractEvents:function(e,t,n,r){var o=void 0,i=void 0;if(he)e:{switch(e){case"compositionstart":o=we.compositionStart;break e;case"compositionend":o=we.compositionEnd;break e;case"compositionupdate":o=we.compositionUpdate;break e}o=void 0}else Ee?ke(e,n)&&(o=we.compositionEnd):"keydown"===e&&229===n.keyCode&&(o=we.compositionStart);return o?(ge&&"ko"!==n.locale&&(Ee||o!==we.compositionStart?o===we.compositionEnd&&Ee&&(i=ie()):(re="value"in(ne=r)?ne.value:ne.textContent,Ee=!0)),o=de.getPooled(o,t,n,r),i?o.data=i:null!==(i=Te(n))&&(o.data=i),$(o),i=o):i=null,(e=ye?function(e,t){switch(e){case"compositionend":return Te(t);case"keypress":return 32!==t.which?null:(xe=!0,be);case"textInput":return(e=t.data)===be&&xe?null:e;default:return null}}(e,n):function(e,t){if(Ee)return"compositionend"===e||!he&&ke(e,t)?(e=ie(),oe=re=ne=null,Ee=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1