liumingyi_1 5 years ago
parent
commit
2bd4f16f37

+ 1 - 0
example/package.json

@@ -11,6 +11,7 @@
     "react-dom": "^16.11.0",
     "react-photo-view": "link:..",
     "react-scripts": "3.2.0",
+    "styled-components": "^4.4.1",
     "typescript": "3.7.2"
   },
   "scripts": {

+ 104 - 2
example/yarn.lock

@@ -904,6 +904,23 @@
   resolved "https://registry.yarnpkg.com/@csstools/normalize.css/-/normalize.css-9.0.1.tgz#c27b391d8457d1e893f1eddeaf5e5412d12ffbb5"
   integrity sha512-6It2EVfGskxZCQhuykrfnALg7oVeiI6KclWSmGDqB0AiInVrTGB9Jp9i4/Ad21u9Jde/voVQz6eFX/eSg/UsPA==
 
+"@emotion/is-prop-valid@^0.8.1":
+  version "0.8.5"
+  resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.5.tgz#2dda0791f0eafa12b7a0a5b39858405cc7bde983"
+  integrity sha512-6ZODuZSFofbxSbcxwsFz+6ioPjb0ISJRRPLZ+WIbjcU2IMU0Io+RGQjjaTgOvNQl007KICBm7zXQaYQEC1r6Bg==
+  dependencies:
+    "@emotion/memoize" "0.7.3"
+
+"@emotion/memoize@0.7.3":
+  version "0.7.3"
+  resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.3.tgz#5b6b1c11d6a6dddf1f2fc996f74cf3b219644d78"
+  integrity sha512-2Md9mH6mvo+ygq1trTeVp2uzAKwE2P7In0cRpD/M9Q70aH8L+rxMLbb3JCN2JoSWsV2O+DdFjfbbXoMoLBczow==
+
+"@emotion/unitless@^0.7.0":
+  version "0.7.4"
+  resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.4.tgz#a87b4b04e5ae14a88d48ebef15015f6b7d1f5677"
+  integrity sha512-kBa+cDHOR9jpRJ+kcGMsysrls0leukrm68DmFQoMIWQcXdr2cZvyvypWuGYT7U+9kAExUE7+T7r6G3C3A6L8MQ==
+
 "@hapi/address@2.x.x":
   version "2.1.2"
   resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.2.tgz#1c794cd6dbf2354d1eb1ef10e0303f573e1c7222"
@@ -1960,6 +1977,21 @@ babel-plugin-named-asset-import@^0.3.4:
   resolved "https://registry.yarnpkg.com/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.4.tgz#4a8fc30e9a3e2b1f5ed36883386ab2d84e1089bd"
   integrity sha512-S6d+tEzc5Af1tKIMbsf2QirCcPdQ+mKUCY2H1nJj1DyA1ShwpsoxEOAwbWsG5gcXNV/olpvQd9vrUWRx4bnhpw==
 
+"babel-plugin-styled-components@>= 1":
+  version "1.10.6"
+  resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.10.6.tgz#f8782953751115faf09a9f92431436912c34006b"
+  integrity sha512-gyQj/Zf1kQti66100PhrCRjI5ldjaze9O0M3emXRPAN80Zsf8+e1thpTpaXJXVHXtaM4/+dJEgZHyS9Its+8SA==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.0.0"
+    "@babel/helper-module-imports" "^7.0.0"
+    babel-plugin-syntax-jsx "^6.18.0"
+    lodash "^4.17.11"
+
+babel-plugin-syntax-jsx@^6.18.0:
+  version "6.18.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"
+  integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=
+
 babel-plugin-syntax-object-rest-spread@^6.8.0:
   version "6.13.0"
   resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5"
@@ -2352,6 +2384,11 @@ camelcase@^5.0.0, camelcase@^5.2.0, camelcase@^5.3.1:
   resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
   integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
 
+camelize@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b"
+  integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=
+
 caniuse-api@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0"
@@ -2841,6 +2878,11 @@ css-blank-pseudo@^0.1.4:
   dependencies:
     postcss "^7.0.5"
 
+css-color-keywords@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
+  integrity sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=
+
 css-color-names@0.0.4, css-color-names@^0.0.4:
   version "0.0.4"
   resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
@@ -2911,6 +2953,15 @@ css-select@^2.0.0:
     domutils "^1.7.0"
     nth-check "^1.0.2"
 
+css-to-react-native@^2.2.2:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-2.3.2.tgz#e75e2f8f7aa385b4c3611c52b074b70a002f2e7d"
+  integrity sha512-VOFaeZA053BqvvvqIA8c9n0+9vFppVBAHCp6JgFTtTMU3Mzi+XnelJ9XC9ul3BqFzZyQ5N+H0SnwsWT2Ebchxw==
+  dependencies:
+    camelize "^1.0.0"
+    css-color-keywords "^1.0.0"
+    postcss-value-parser "^3.3.0"
+
 css-tree@1.0.0-alpha.29:
   version "1.0.0-alpha.29"
   resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.29.tgz#3fa9d4ef3142cbd1c301e7664c1f352bd82f5a39"
@@ -5158,6 +5209,11 @@ is-typedarray@~1.0.0:
   resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
   integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
 
+is-what@^3.3.1:
+  version "3.3.1"
+  resolved "https://registry.yarnpkg.com/is-what/-/is-what-3.3.1.tgz#79502181f40226e2d8c09226999db90ef7c1bcbe"
+  integrity sha512-seFn10yAXy+yJlTRO+8VfiafC+0QJanGLMPTBWLrJm/QPauuchy0UXh8B6H5o9VA8BAzk0iYievt6mNp6gfaqA==
+
 is-windows@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
@@ -6091,6 +6147,11 @@ mem@^4.0.0:
     mimic-fn "^2.0.0"
     p-is-promise "^2.0.0"
 
+memoize-one@^5.0.0:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0"
+  integrity sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==
+
 memory-fs@^0.4.0, memory-fs@^0.4.1:
   version "0.4.1"
   resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
@@ -6099,6 +6160,13 @@ memory-fs@^0.4.0, memory-fs@^0.4.1:
     errno "^0.1.3"
     readable-stream "^2.0.1"
 
+merge-anything@^2.2.4:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/merge-anything/-/merge-anything-2.4.1.tgz#e9bccaec1e49ec6cb5f77ca78c5770d1a35315e6"
+  integrity sha512-dYOIAl9GFCJNctSIHWOj9OJtarCjsD16P8ObCl6oxrujAG+kOvlwJuOD9/O9iYZ9aTi1RGpGTG9q9etIvuUikQ==
+  dependencies:
+    is-what "^3.3.1"
+
 merge-deep@^3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/merge-deep/-/merge-deep-3.0.2.tgz#f39fa100a4f1bd34ff29f7d2bf4508fbb8d83ad2"
@@ -7842,7 +7910,7 @@ prompts@^2.0.1:
     kleur "^3.0.3"
     sisteransi "^1.0.3"
 
-prop-types@^15.6.2, prop-types@^15.7.2:
+prop-types@^15.5.4, prop-types@^15.6.2, prop-types@^15.7.2:
   version "15.7.2"
   resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
   integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@@ -8064,6 +8132,11 @@ react-error-overlay@^6.0.3:
   resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.3.tgz#c378c4b0a21e88b2e159a3e62b2f531fd63bf60d"
   integrity sha512-bOUvMWFQVk5oz8Ded9Xb7WVdEi3QGLC8tH7HmYP0Fdp4Bn3qw0tRFmr5TW6mvahzvmrK4a6bqWGfCevBflP+Xw==
 
+react-is@^16.6.0:
+  version "16.11.0"
+  resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.11.0.tgz#b85dfecd48ad1ce469ff558a882ca8e8313928fa"
+  integrity sha512-gbBVYR2p8mnriqAwWx9LbuUrShnAuSCNnuPGyc7GJrMVQtPDAh8iLpv7FRuMPFb56KkaVZIYSz1PrjI9q0QPCw==
+
 react-is@^16.8.1, react-is@^16.8.4:
   version "16.10.1"
   resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.10.1.tgz#0612786bf19df406502d935494f0450b40b8294f"
@@ -9193,6 +9266,25 @@ style-loader@1.0.0:
     loader-utils "^1.2.3"
     schema-utils "^2.0.1"
 
+styled-components@^4.4.1:
+  version "4.4.1"
+  resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-4.4.1.tgz#e0631e889f01db67df4de576fedaca463f05c2f2"
+  integrity sha512-RNqj14kYzw++6Sr38n7197xG33ipEOktGElty4I70IKzQF1jzaD1U4xQ+Ny/i03UUhHlC5NWEO+d8olRCDji6g==
+  dependencies:
+    "@babel/helper-module-imports" "^7.0.0"
+    "@babel/traverse" "^7.0.0"
+    "@emotion/is-prop-valid" "^0.8.1"
+    "@emotion/unitless" "^0.7.0"
+    babel-plugin-styled-components ">= 1"
+    css-to-react-native "^2.2.2"
+    memoize-one "^5.0.0"
+    merge-anything "^2.2.4"
+    prop-types "^15.5.4"
+    react-is "^16.6.0"
+    stylis "^3.5.0"
+    stylis-rule-sheet "^0.0.10"
+    supports-color "^5.5.0"
+
 stylehacks@^4.0.0:
   version "4.0.3"
   resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5"
@@ -9202,12 +9294,22 @@ stylehacks@^4.0.0:
     postcss "^7.0.0"
     postcss-selector-parser "^3.0.0"
 
+stylis-rule-sheet@^0.0.10:
+  version "0.0.10"
+  resolved "https://registry.yarnpkg.com/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz#44e64a2b076643f4b52e5ff71efc04d8c3c4a430"
+  integrity sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw==
+
+stylis@^3.5.0:
+  version "3.5.4"
+  resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.4.tgz#f665f25f5e299cf3d64654ab949a57c768b73fbe"
+  integrity sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q==
+
 supports-color@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
   integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
 
-supports-color@^5.3.0:
+supports-color@^5.3.0, supports-color@^5.5.0:
   version "5.5.0"
   resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
   integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==

+ 6 - 4
package.json

@@ -35,12 +35,13 @@
     "lodash.uniqueid": "^4.0.1"
   },
   "peerDependencies": {
-    "react": "^16.0.0",
-    "react-dom": "^16.0.0",
-    "styled-components": "^4.0.0"
+    "classnames": "^2.2.0",
+    "react": "^16.8.0",
+    "react-dom": "^16.8.0"
   },
   "devDependencies": {
     "@svgr/rollup": "^4.3.3",
+    "@types/classnames": "^2.2.9",
     "@types/jest": "^24.0.22",
     "@types/lodash.debounce": "^4.0.6",
     "@types/lodash.uniqueid": "^4.0.6",
@@ -49,8 +50,10 @@
     "@types/styled-components": "^4.1.21",
     "babel-core": "^6.26.3",
     "babel-runtime": "^6.26.0",
+    "classnames": "^2.2.6",
     "cross-env": "^6.0.3",
     "gh-pages": "^2.1.1",
+    "less": "^3.10.3",
     "prettier": "^1.18.2",
     "react": "^16.11.0",
     "react-dom": "^16.11.0",
@@ -63,7 +66,6 @@
     "rollup-plugin-postcss": "^2.0.3",
     "rollup-plugin-typescript2": "^0.25.2",
     "rollup-plugin-url": "^3.0.0",
-    "styled-components": "^4.4.1",
     "typescript": "^3.7.2"
   },
   "files": [

+ 3 - 1
rollup.config.js

@@ -26,7 +26,9 @@ export default {
   ],
   plugins: [
     external(),
-    postcss(),
+    postcss({
+      extract: `dist/index.css`,
+    }),
     url(),
     svgr(),
     resolve(),

+ 8 - 0
src/Photo.less

@@ -0,0 +1,8 @@
+.PhotoView__Photo {
+  will-change: transform;
+  cursor: grab;
+
+  &:active {
+    cursor: grabbing;
+  }
+}

+ 15 - 16
src/Photo.tsx

@@ -1,11 +1,13 @@
 import React from 'react';
-import styled from 'styled-components';
+import classNames from 'classnames';
 import throttle from './utils/throttle';
 import Spinner from './components/Spinner';
 import getSuitableImageSize from './utils/getSuitableImageSize';
+import './Photo.less';
 
 export interface IPhotoProps extends React.HTMLAttributes<any> {
   src: string;
+  className?: string;
   onPhotoResize: () => void;
   loadingElement?: JSX.Element;
   brokenElement?: JSX.Element;
@@ -20,16 +22,10 @@ type PhotoState = {
   height: number;
 };
 
-const PhotoImage = styled.img`
-  will-change: transform;
-  cursor: grab;
-
-  &:active {
-    cursor: grabbing;
-  }
-`;
-
-export default class Photo extends React.PureComponent<IPhotoProps, PhotoState> {
+export default class Photo extends React.PureComponent<
+  IPhotoProps,
+  PhotoState
+> {
   static displayName = 'Photo';
 
   readonly state = {
@@ -62,7 +58,7 @@ export default class Photo extends React.PureComponent<IPhotoProps, PhotoState>
     window.removeEventListener('resize', this.handleResize);
   }
 
-  handleImageLoaded = (e) => {
+  handleImageLoaded = e => {
     const { naturalWidth, naturalHeight } = e.target;
     if (this.isMount) {
       this.setState({
@@ -72,7 +68,7 @@ export default class Photo extends React.PureComponent<IPhotoProps, PhotoState>
         ...getSuitableImageSize(naturalWidth, naturalHeight),
       });
     }
-  }
+  };
 
   handleImageBroken = () => {
     if (this.isMount) {
@@ -80,7 +76,7 @@ export default class Photo extends React.PureComponent<IPhotoProps, PhotoState>
         broken: true,
       });
     }
-  }
+  };
 
   handleResize = () => {
     const { loaded, naturalWidth, naturalHeight } = this.state;
@@ -90,11 +86,12 @@ export default class Photo extends React.PureComponent<IPhotoProps, PhotoState>
         this.props.onPhotoResize,
       );
     }
-  }
+  };
 
   render() {
     const {
       src,
+      className,
       loadingElement,
       brokenElement,
       ...restProps
@@ -104,10 +101,12 @@ export default class Photo extends React.PureComponent<IPhotoProps, PhotoState>
     if (src && !broken) {
       if (loaded) {
         return (
-          <PhotoImage
+          <img
+            className={classNames('PhotoView__Photo', className)}
             src={src}
             width={width}
             height={height}
+            alt=""
             {...restProps}
           />
         );

+ 18 - 21
src/PhotoConsumer.tsx

@@ -39,7 +39,7 @@ class PhotoViewItem extends React.Component<IPhotoViewItem, PhotoViewState> {
     removeItem(this.key);
   }
 
-  handleTouchStart = (e) => {
+  handleTouchStart = e => {
     const { clientX, clientY } = e.touches[0];
     this.setState({
       clientX,
@@ -52,9 +52,9 @@ class PhotoViewItem extends React.Component<IPhotoViewItem, PhotoViewState> {
         onTouchStart(e);
       }
     }
-  }
+  };
 
-  handleTouchEnd = (e) => {
+  handleTouchEnd = e => {
     const { onShow, children } = this.props;
     const { clientX: newClientX, clientY: newClientY } = e.changedTouches[0];
     const { clientX, clientY } = this.state;
@@ -67,9 +67,9 @@ class PhotoViewItem extends React.Component<IPhotoViewItem, PhotoViewState> {
         onTouchEnd(e);
       }
     }
-  }
+  };
 
-  handleClick = (e) => {
+  handleClick = e => {
     const { onShow, children } = this.props;
     onShow(this.key);
     if (children) {
@@ -78,20 +78,22 @@ class PhotoViewItem extends React.Component<IPhotoViewItem, PhotoViewState> {
         onClick(e);
       }
     }
-  }
+  };
 
   render() {
     const { children } = this.props;
     if (children) {
-      return React.Children.only(React.cloneElement(
-        children,
-        isMobile
-          ? {
-            onTouchStart: this.handleTouchStart,
-            onTouchEnd: this.handleTouchEnd,
-          }
-          : { onClick: this.handleClick },
-      ));
+      return React.Children.only(
+        React.cloneElement(
+          children,
+          isMobile
+            ? {
+                onTouchStart: this.handleTouchStart,
+                onTouchEnd: this.handleTouchEnd,
+              }
+            : { onClick: this.handleClick },
+        ),
+      );
     }
     return null;
   }
@@ -111,12 +113,7 @@ const PhotoConsumer: React.SFC<IPhotoConsumer> = ({
 }) => (
   <PhotoContext.Consumer>
     {value => (
-      <PhotoViewItem
-        {...value}
-        {...restProps}
-        src={src}
-        intro={intro}
-      >
+      <PhotoViewItem {...value} {...restProps} src={src} intro={intro}>
         {children}
       </PhotoViewItem>
     )}

+ 6 - 9
src/PhotoProvider.tsx

@@ -45,7 +45,7 @@ export default class PhotoProvider extends React.Component<
         intro,
       }),
     }));
-  }
+  };
 
   handleRemoveItem = (key: string) => {
     this.setState(({ images, index }) => {
@@ -56,7 +56,7 @@ export default class PhotoProvider extends React.Component<
         index: Math.min(nextEndIndex, index),
       };
     });
-  }
+  };
 
   handleShow = (key: string) => {
     const { images } = this.state;
@@ -64,25 +64,22 @@ export default class PhotoProvider extends React.Component<
       visible: true,
       index: images.findIndex(item => item.key === key),
     });
-  }
+  };
 
   handleClose = () => {
     this.setState({
       visible: false,
     });
-  }
+  };
 
   handleIndexChange = (index: number) => {
     this.setState({
       index,
     });
-  }
+  };
 
   render() {
-    const {
-      children,
-      ...restProps
-    } = this.props;
+    const { children, ...restProps } = this.props;
     const { images, visible, index } = this.state;
 
     return (

+ 65 - 0
src/PhotoSlider.less

@@ -0,0 +1,65 @@
+.PhotoView {
+  &-PhotoSlider__Backdrop {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    background: rgba(0, 0, 0, 0.6);
+    z-index: -1;
+  }
+
+  &-PhotoSlider__BannerWrap {
+    position: absolute;
+    left: 0;
+    top: 0;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    width: 100%;
+    height: 44px;
+    color: white;
+    background-color: rgba(0, 0, 0, 0.5);
+    transition: opacity 0.2s ease-out;
+    z-index: 20;
+  }
+
+  &-PhotoSlider__Counter {
+    padding: 0 10px;
+    font-size: 14px;
+    opacity: 0.75;
+  }
+
+  &-PhotoSlider__BannerRight {
+    height: 100%;
+  }
+
+  &-PhotoSlider__Close {
+    box-sizing: border-box;
+    padding: 10px;
+    opacity: 0.75;
+    cursor: pointer;
+    transition: opacity 0.2s linear;
+
+    &:hover {
+      opacity: 1;
+    }
+  }
+
+  &-PhotoSlider__FooterWrap {
+    box-sizing: border-box;
+    position: absolute;
+    left: 0;
+    bottom: 0;
+    padding: 10px;
+    width: 100%;
+    min-height: 44px;
+    line-height: 1.5;
+    font-size: 14px;
+    color: #ccc;
+    background-color: rgba(0, 0, 0, 0.5);
+    text-align: justify;
+    transition: opacity 0.2s ease-out;
+    z-index: 20;
+  }
+}

+ 58 - 41
src/PhotoSlider.tsx

@@ -1,14 +1,10 @@
 import React from 'react';
+import classNames from 'classnames';
 import PhotoView from './PhotoView';
 import SlideWrap from './components/SlideWrap';
-import Backdrop from './components/Backdrop';
-import { Close, Counter, BannerWrap, BannerRight } from './components/BannerWrap';
-import FooterWrap from './components/FooterWrap';
+import CloseSVG from './components/CloseSVG';
 import isMobile from './utils/isMobile';
-import {
-  dataType,
-  IPhotoProviderBase,
-} from './types';
+import { dataType, IPhotoProviderBase } from './types';
 import { defaultOpacity, horizontalOffset, maxMoveOffset } from './variables';
 
 export interface IPhotoSliderProps extends IPhotoProviderBase {
@@ -104,7 +100,7 @@ export default class PhotoSlider extends React.Component<
     this.setState({
       overlayVisible: true,
     });
-  }
+  };
 
   handlePhotoTap = () => {
     if (this.props.photoClosable) {
@@ -114,13 +110,13 @@ export default class PhotoSlider extends React.Component<
         overlayVisible: !prevState.overlayVisible,
       }));
     }
-  }
+  };
 
   handlePhotoMaskTap = () => {
     if (this.props.maskClosable) {
       this.handleClose();
     }
-  }
+  };
 
   handleResize = () => {
     const { innerWidth } = window;
@@ -131,7 +127,7 @@ export default class PhotoSlider extends React.Component<
         lastClientY: undefined,
       };
     });
-  }
+  };
 
   handleReachVerticalMove = (_, clientY) => {
     this.setState(({ lastClientY, backdropOpacity }) => {
@@ -154,9 +150,9 @@ export default class PhotoSlider extends React.Component<
         photoScale: Math.max(Math.min(1, 1 - offsetClientY / 100 / 10), 0.6),
       };
     });
-  }
+  };
 
-  handleReachHorizontalMove = (clientX) => {
+  handleReachHorizontalMove = clientX => {
     const { innerWidth } = window;
     this.setState(({ lastClientX, translateX, photoIndex }) => {
       if (lastClientX === undefined) {
@@ -170,10 +166,11 @@ export default class PhotoSlider extends React.Component<
       return {
         touched: true,
         lastClientX: lastClientX,
-        translateX: -(innerWidth + horizontalOffset) * photoIndex + offsetClientX,
+        translateX:
+          -(innerWidth + horizontalOffset) * photoIndex + offsetClientX,
       };
     });
-  }
+  };
 
   handleIndexChange = (photoIndex: number) => {
     const singlePageWidth = window.innerWidth + horizontalOffset;
@@ -186,7 +183,7 @@ export default class PhotoSlider extends React.Component<
     if (onIndexChange) {
       onIndexChange(photoIndex);
     }
-  }
+  };
 
   handleReachUp = (clientX: number, clientY: number) => {
     const { innerWidth, innerHeight } = window;
@@ -211,7 +208,10 @@ export default class PhotoSlider extends React.Component<
       isChangeVisible = true;
       onClose();
       // 下一张
-    } else if (offsetClientX < -maxMoveOffset && photoIndex < images.length - 1) {
+    } else if (
+      offsetClientX < -maxMoveOffset &&
+      photoIndex < images.length - 1
+    ) {
       currentPhotoIndex = photoIndex + 1;
       currentTranslateX = -singlePageWidth * currentPhotoIndex;
       if (onIndexChange) {
@@ -235,7 +235,7 @@ export default class PhotoSlider extends React.Component<
       photoScale: 1,
       overlayVisible: isChangeVisible ? true : overlayVisible,
     });
-  }
+  };
 
   render() {
     const {
@@ -271,31 +271,40 @@ export default class PhotoSlider extends React.Component<
 
       return (
         <SlideWrap className={className}>
-          <Backdrop
-            className={maskClassName}
+          <div
+            className={classNames(
+              'PhotoView_PhotoSlide__Backdrop',
+              maskClassName,
+            )}
             style={{ background: `rgba(0, 0, 0, ${backdropOpacity})` }}
           />
           {bannerVisible && (
-            <BannerWrap style={overlayStyle}>
-              <Counter>{photoIndex + 1} / {imageLength}</Counter>
-              <BannerRight>
-                <Close
+            <div
+              className="PhotoView-PhotoSlider__BannerWrap"
+              style={overlayStyle}
+            >
+              <div className="PhotoView-PhotoSlider__Counter">
+                {photoIndex + 1} / {imageLength}
+              </div>
+              <div className="PhotoView-PhotoSlider__BannerRight">
+                <CloseSVG
+                  className="PhotoView-PhotoSlider__Close"
                   onTouchEnd={isMobile ? onClose : undefined}
                   onClick={isMobile ? undefined : onClose}
                 />
-              </BannerRight>
-            </BannerWrap>
+              </div>
+            </div>
           )}
           {images
-            .slice( // 加载相邻三张
+            .slice(
+              // 加载相邻三张
               Math.max(photoIndex - 1, 0),
-              Math.min(photoIndex + 2, imageLength + 1)
+              Math.min(photoIndex + 2, imageLength + 1),
             )
             .map((item: dataType, index) => {
               // 截取之前的索引位置
-              const realIndex = photoIndex === 0
-                ? photoIndex + index
-                : photoIndex - 1 + index;
+              const realIndex =
+                photoIndex === 0 ? photoIndex + index : photoIndex - 1 + index;
               return (
                 <PhotoView
                   key={item.key || realIndex}
@@ -330,16 +339,24 @@ export default class PhotoSlider extends React.Component<
               );
             })}
           {introVisible && overlayIntro ? (
-            <FooterWrap style={overlayStyle}>{overlayIntro}</FooterWrap>
-          ) : undefined}
-          {overlayRender && overlayRender({
-            images,
-            index: photoIndex,
-            visible,
-            onClose,
-            onIndexChange: this.handleIndexChange,
-            overlayVisible,
-          })}
+            <div
+              className="PhotoView-PhotoSlider__FooterWrap"
+              style={overlayStyle}
+            >
+              {overlayIntro}
+            </div>
+          ) : (
+            undefined
+          )}
+          {overlayRender &&
+            overlayRender({
+              images,
+              index: photoIndex,
+              visible,
+              onClose,
+              onIndexChange: this.handleIndexChange,
+              overlayVisible,
+            })}
         </SlideWrap>
       );
     }

+ 23 - 0
src/PhotoView.less

@@ -0,0 +1,23 @@
+.PhotoView {
+  &__PhotoWrap {
+    position: absolute;
+    top: 0;
+    left: 0;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    width: 100%;
+    height: 100%;
+    z-index: 10;
+    overflow: hidden;
+  }
+
+  &__PhotoMask {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    z-index: -1;
+  }
+}

+ 23 - 22
src/PhotoView.tsx

@@ -1,7 +1,6 @@
 import React from 'react';
+import classNames from 'classnames';
 import Photo from './Photo';
-import PhotoWrap from './components/PhotoWrap';
-import PhotoMask from './components/PhotoMask';
 import throttle from './utils/throttle';
 import isMobile from './utils/isMobile';
 import getMultipleTouchPosition from './utils/getMultipleTouchPosition';
@@ -15,6 +14,7 @@ import {
   PhotoTapFunction,
   ReachTypeEnum,
 } from './types';
+import './PhotoView.less';
 
 export interface IPhotoViewProps {
   // 图片地址
@@ -131,7 +131,7 @@ export default class PhotoView extends React.Component<
       lastTouchLength: touchLength,
       touchedTime: Date.now(),
     }));
-  }
+  };
 
   onMove = (newClientX: number, newClientY: number, touchLength: number = 0) => {
     const { touched, maskTouched } = this.state;
@@ -198,14 +198,14 @@ export default class PhotoView extends React.Component<
         });
       }
     }
-  }
+  };
 
   onPhotoTap = (clientX: number, clientY: number) => {
     const { onPhotoTap } = this.props;
     if (onPhotoTap) {
       onPhotoTap(clientX, clientY);
     }
-  }
+  };
 
   onDoubleTap: TapFuncType<number> = (clientX, clientY) => {
     const { current } = this.photoRef;
@@ -226,7 +226,7 @@ export default class PhotoView extends React.Component<
         }),
       });
     }
-  }
+  };
 
   handleWheel = (e) => {
     e.preventDefault();
@@ -258,7 +258,7 @@ export default class PhotoView extends React.Component<
         };
       });
     }
-  }
+  };
 
   handleMaskStart = (clientX: number, clientY: number) => {
     this.setState(prevState => ({
@@ -268,16 +268,16 @@ export default class PhotoView extends React.Component<
       lastX: prevState.x,
       lastY: prevState.y,
     }));
-  }
+  };
 
   handleMaskMouseDown = (e) => {
     this.handleMaskStart(e.clientX, e.clientY);
-  }
+  };
 
   handleMaskTouchStart = (e) => {
     const { clientX, clientY } = e.touches[0];
     this.handleMaskStart(clientX, clientY);
-  }
+  };
 
   handleTouchStart = (e) => {
     if (e.touches.length >= 2) {
@@ -287,12 +287,12 @@ export default class PhotoView extends React.Component<
       const { clientX, clientY } = e.touches[0];
       this.handleStart(clientX, clientY);
     }
-  }
+  };
 
   handleMouseDown = (e) => {
     e.preventDefault();
     this.handleStart(e.clientX, e.clientY);
-  }
+  };
 
   handleTouchMove = (e) => {
     e.preventDefault();
@@ -303,12 +303,12 @@ export default class PhotoView extends React.Component<
       const { clientX, clientY } = e.touches[0];
       this.onMove(clientX, clientY);
     }
-  }
+  };
 
   handleMouseMove = (e) => {
     e.preventDefault();
     this.onMove(e.clientX, e.clientY);
-  }
+  };
 
   handleUp = (newClientX: number, newClientY: number) => {
     const { touched, maskTouched } = this.state;
@@ -361,17 +361,17 @@ export default class PhotoView extends React.Component<
         }
       });
     }
-  }
+  };
 
   handleTouchEnd = (e) => {
     const { clientX, clientY } = e.changedTouches[0];
     this.handleUp(clientX, clientY);
-  }
+  };
 
   handleMouseUp = (e) => {
     const { clientX, clientY } = e;
     this.handleUp(clientX, clientY);
-  }
+  };
 
   handleResize = () => {
     this.setState(initialState);
@@ -379,7 +379,7 @@ export default class PhotoView extends React.Component<
     if (onPhotoResize) {
       onPhotoResize();
     }
-  }
+  };
 
   handleReachCallback = ({
     x,
@@ -447,7 +447,7 @@ export default class PhotoView extends React.Component<
       return ReachTypeEnum.YReach;
     }
     return ReachTypeEnum.Normal;
-  }
+  };
 
   render() {
     const {
@@ -464,8 +464,9 @@ export default class PhotoView extends React.Component<
     const transform = `translate3d(${x}px, ${y}px, 0) scale(${scale * photoScale})`;
 
     return (
-      <PhotoWrap className={wrapClassName} style={style}>
-        <PhotoMask
+      <div className={classNames('PhotoView__PhotoWrap', wrapClassName)} style={style}>
+        <div
+          className="PhotoView__PhotoMask"
           onMouseDown={isMobile ? undefined : this.handleMaskMouseDown}
           onTouchStart={isMobile ? this.handleMaskTouchStart : undefined}
         />
@@ -487,7 +488,7 @@ export default class PhotoView extends React.Component<
           loadingElement={loadingElement}
           brokenElement={brokenElement}
         />
-      </PhotoWrap>
+      </div>
     );
   }
 }

+ 0 - 13
src/components/Backdrop.tsx

@@ -1,13 +0,0 @@
-import styled from 'styled-components';
-
-const Backdrop = styled.div`
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  background: rgba(0, 0, 0, 0.6);
-  z-index: -1;
-`;
-
-export default Backdrop;

+ 0 - 57
src/components/BannerWrap.tsx

@@ -1,57 +0,0 @@
-import React from 'react';
-import styled from 'styled-components';
-
-export const BannerWrap = styled.div`
-  position: absolute;
-  left: 0;
-  top: 0;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  width: 100%;
-  height: 44px;
-  color: white;
-  background-color: rgba(0, 0, 0, 0.5);
-  transition: opacity 0.2s ease-out;
-  z-index: 20;
-`;
-
-export const Counter = styled.div`
-  padding: 0 10px;
-  font-size: 14px;
-  opacity: 0.75;
-`;
-
-export const BannerRight = styled.div`
-  height: 100%;
-`;
-
-function CloseSVG(props) {
-  return (
-    <svg
-      version="1.1"
-      xmlns="http://www.w3.org/2000/svg"
-      width="44"
-      height="44"
-      viewBox="0 0 768 768"
-      {...props}
-    >
-      <path
-        fill="#FFF"
-        d="M607.5 205.5l-178.5 178.5 178.5 178.5-45 45-178.5-178.5-178.5 178.5-45-45 178.5-178.5-178.5-178.5 45-45 178.5 178.5 178.5-178.5z"
-      />
-    </svg>
-  );
-}
-
-export const Close = styled(CloseSVG)<React.HTMLAttributes<any>>`
-  box-sizing: border-box;
-  padding: 10px;
-  opacity: 0.75;
-  cursor: pointer;
-  transition: opacity 0.2s linear;
-
-  &:hover {
-    opacity: 1;
-  }
-`;

+ 22 - 0
src/components/CloseSVG.tsx

@@ -0,0 +1,22 @@
+import React from 'react';
+
+function CloseSVG(props) {
+  return (
+    <svg
+      className=""
+      version="1.1"
+      xmlns="http://www.w3.org/2000/svg"
+      width="44"
+      height="44"
+      viewBox="0 0 768 768"
+      {...props}
+    >
+      <path
+        fill="#FFF"
+        d="M607.5 205.5l-178.5 178.5 178.5 178.5-45 45-178.5-178.5-178.5 178.5-45-45 178.5-178.5-178.5-178.5 45-45 178.5 178.5 178.5-178.5z"
+      />
+    </svg>
+  );
+}
+
+export default CloseSVG;

+ 0 - 20
src/components/FooterWrap.tsx

@@ -1,20 +0,0 @@
-import styled from 'styled-components';
-
-const FooterWrap = styled.div`
-  box-sizing: border-box;
-  position: absolute;
-  left: 0;
-  bottom: 0;
-  padding: 10px;
-  width: 100%;
-  min-height: 44px;
-  line-height: 1.5;
-  font-size: 14px;
-  color: #ccc;
-  background-color: rgba(0, 0, 0, 0.5);
-  text-align: justify;
-  transition: opacity 0.2s ease-out;
-  z-index: 20;
-`;
-
-export default FooterWrap;

+ 0 - 12
src/components/PhotoMask.tsx

@@ -1,12 +0,0 @@
-import styled from 'styled-components';
-
-const PhotoMask = styled.div`
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  z-index: -1;
-`;
-
-export default PhotoMask;

+ 0 - 16
src/components/PhotoWrap.tsx

@@ -1,16 +0,0 @@
-import styled from 'styled-components';
-
-const PhotoWrap = styled.section`
-  position: absolute;
-  top: 0;
-  left: 0;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  width: 100%;
-  height: 100%;
-  z-index: 10;
-  overflow: hidden;
-`;
-
-export default PhotoWrap;

+ 11 - 0
src/components/SlideWrap.less

@@ -0,0 +1,11 @@
+.PhotoView {
+  &__SlideWrap {
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    z-index: 2000;
+    overflow: hidden;
+  }
+}

+ 41 - 62
src/components/SlideWrap.tsx

@@ -1,65 +1,44 @@
 import React from 'react';
 import { createPortal } from 'react-dom';
-import styled from 'styled-components';
-
-const Container = styled.div`
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  z-index: 2000;
-  overflow: hidden;
-`;
-
-export default class SlideWrap extends React.Component<{
-  className?: string;
-  children: any;
-}> {
-  static displayName = 'SlideWrap';
-
-  private dialogNode;
-  private originalOverflow;
-
-  constructor(props) {
-    super(props);
-
+import classNames from 'classnames';
+import './SlideWrap.less';
+
+const SlideWrap: React.FC<{ className?: string }> = ({
+  className,
+  children,
+}) => {
+  const [dialogNode] = React.useState(() => {
     // 创建容器
-    this.dialogNode = document.createElement('section');
-    document.body.appendChild(this.dialogNode);
-  }
-
-  componentDidMount() {
-    this.preventScroll();
-  }
-
-  componentWillUnmount() {
-    this.allowScroll();
-    // 清除容器
-    document.body.removeChild(this.dialogNode);
-    this.dialogNode = undefined;
-  }
-
-  preventScroll = () => {
-    const { style } = document.body;
-    this.originalOverflow = style.overflow;
-    style.overflow = 'hidden';
-  }
-
-  allowScroll = () => {
-    const { style } = document.body;
-    style.overflow = this.originalOverflow;
-    this.originalOverflow = undefined;
-  }
-
-  render() {
-    const { className, children } = this.props;
-
-    return createPortal(
-      <Container className={className}>
-        {children}
-      </Container>,
-      this.dialogNode,
-    );
-  }
-}
+    const dialogNode = document.createElement('section');
+    document.body.appendChild(dialogNode);
+    return dialogNode;
+  });
+  const originalOverflowCallback = React.useRef('');
+
+  React.useEffect(
+    () => {
+      const { style } = document.body;
+      originalOverflowCallback.current = style.overflow;
+      style.overflow = 'hidden';
+
+      return () => {
+        const { style } = document.body;
+        style.overflow = originalOverflowCallback.current;
+        // 清除容器
+        document.body.removeChild(dialogNode);
+      };
+    },
+    [] as readonly [],
+  );
+
+  return createPortal(
+    <div className={classNames('PhotoView__SlideWrap', className)}>
+      {children}
+    </div>,
+    dialogNode,
+  );
+};
+
+SlideWrap.displayName = 'SlideWrap';
+
+export default SlideWrap;

+ 15 - 0
src/components/Spinner.less

@@ -0,0 +1,15 @@
+@keyframes PhotoView__rotate {
+  from {
+    transform: rotate(0deg);
+  }
+
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+.PhotoView {
+  &__Spinner {
+    animation: PhotoView__rotate 0.6s linear infinite;
+  }
+}

+ 4 - 18
src/components/Spinner.tsx

@@ -1,12 +1,10 @@
 import React from 'react';
-import styled, { keyframes } from 'styled-components';
+import './Spinner.less';
 
-function Spinner(props: {
-  className?: string;
-}) {
+function Spinner() {
   return (
     <svg
-      className={props.className}
+      className="PhotoView__Spinner"
       xmlns="http://www.w3.org/2000/svg"
       viewBox="0 0 32 32"
       width="36"
@@ -22,16 +20,4 @@ function Spinner(props: {
   );
 }
 
-const rotate = keyframes`
-  from {
-    transform: rotate(0deg);
-  }
-
-  to {
-    transform: rotate(360deg);
-  }
-`;
-
-export default styled(Spinner)`
-  animation: ${rotate} 0.6s linear infinite;
-`;
+export default Spinner;

+ 2 - 2
src/utils/getCloseEdge.ts

@@ -5,7 +5,7 @@ import { CloseEdgeEnum } from '../types';
  * @param x
  * @param scale
  * @param width
- * @return 0. 未超出 1. 小于屏幕宽度 2. 接触左边 3. 接触右边
+ * @return CloseEdgeEnum
  */
 export const getClosedHorizontal = (
   x: number,
@@ -31,7 +31,7 @@ export const getClosedHorizontal = (
  * @param y
  * @param scale
  * @param height
- * @return 0. 未超出 1. 小于屏幕高度 2. 接触上边 3. 接触下边
+ * @return CloseEdgeEnum
  */
 export const getClosedVertical = (
   y: number,

+ 52 - 101
yarn.lock

@@ -126,7 +126,7 @@
   dependencies:
     "@babel/types" "^7.7.0"
 
-"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.7.0":
+"@babel/helper-module-imports@^7.7.0":
   version "7.7.0"
   resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.7.0.tgz#99c095889466e5f7b6d66d98dffc58baaf42654d"
   integrity sha512-Dv3hLKIC1jyfTkClvyEkYP2OlkzNvWs5+Q8WgPbxM5LMeorons7iPP91JM+DU7tRbhqA1ZeooPaMFvQrn23RHw==
@@ -692,7 +692,7 @@
     "@babel/parser" "^7.7.0"
     "@babel/types" "^7.7.0"
 
-"@babel/traverse@^7.0.0", "@babel/traverse@^7.7.0":
+"@babel/traverse@^7.7.0":
   version "7.7.0"
   resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.7.0.tgz#9f5744346b8d10097fd2ec2eeffcaf19813cbfaf"
   integrity sha512-ea/3wRZc//e/uwCpuBX2itrhI0U9l7+FsrKWyKGNyvWbuMcCG7ATKY2VI4wlg2b2TA39HHwIxnvmXvtiKsyn7w==
@@ -716,23 +716,6 @@
     lodash "^4.17.13"
     to-fast-properties "^2.0.0"
 
-"@emotion/is-prop-valid@^0.8.1":
-  version "0.8.5"
-  resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.5.tgz#2dda0791f0eafa12b7a0a5b39858405cc7bde983"
-  integrity sha512-6ZODuZSFofbxSbcxwsFz+6ioPjb0ISJRRPLZ+WIbjcU2IMU0Io+RGQjjaTgOvNQl007KICBm7zXQaYQEC1r6Bg==
-  dependencies:
-    "@emotion/memoize" "0.7.3"
-
-"@emotion/memoize@0.7.3":
-  version "0.7.3"
-  resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.3.tgz#5b6b1c11d6a6dddf1f2fc996f74cf3b219644d78"
-  integrity sha512-2Md9mH6mvo+ygq1trTeVp2uzAKwE2P7In0cRpD/M9Q70aH8L+rxMLbb3JCN2JoSWsV2O+DdFjfbbXoMoLBczow==
-
-"@emotion/unitless@^0.7.0":
-  version "0.7.4"
-  resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.4.tgz#a87b4b04e5ae14a88d48ebef15015f6b7d1f5677"
-  integrity sha512-kBa+cDHOR9jpRJ+kcGMsysrls0leukrm68DmFQoMIWQcXdr2cZvyvypWuGYT7U+9kAExUE7+T7r6G3C3A6L8MQ==
-
 "@svgr/babel-plugin-add-jsx-attribute@^4.2.0":
   version "4.2.0"
   resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz#dadcb6218503532d6884b210e7f3c502caaa44b1"
@@ -836,6 +819,11 @@
     "@svgr/plugin-svgo" "^4.3.1"
     rollup-pluginutils "^2.8.1"
 
+"@types/classnames@^2.2.9":
+  version "2.2.9"
+  resolved "https://registry.yarnpkg.com/@types/classnames/-/classnames-2.2.9.tgz#d868b6febb02666330410fe7f58f3c4b8258be7b"
+  integrity sha512-MNl+rT5UmZeilaPxAVs6YaPC2m6aA8rofviZbhbxpPpl61uKodfdQVsBtgJGTqGizEf02oW3tsVe7FYB8kK14A==
+
 "@types/estree@*", "@types/estree@0.0.39":
   version "0.0.39"
   resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
@@ -1572,16 +1560,6 @@ babel-plugin-jest-hoist@^22.4.4:
   resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.4.4.tgz#b9851906eab34c7bf6f8c895a2b08bea1a844c0b"
   integrity sha512-DUvGfYaAIlkdnygVIEl0O4Av69NtuQWcrjMOv6DODPuhuGLDnbsARz3AwiiI/EkIMMlxQDUcrZ9yoyJvTNjcVQ==
 
-"babel-plugin-styled-components@>= 1":
-  version "1.10.6"
-  resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.10.6.tgz#f8782953751115faf09a9f92431436912c34006b"
-  integrity sha512-gyQj/Zf1kQti66100PhrCRjI5ldjaze9O0M3emXRPAN80Zsf8+e1thpTpaXJXVHXtaM4/+dJEgZHyS9Its+8SA==
-  dependencies:
-    "@babel/helper-annotate-as-pure" "^7.0.0"
-    "@babel/helper-module-imports" "^7.0.0"
-    babel-plugin-syntax-jsx "^6.18.0"
-    lodash "^4.17.11"
-
 babel-plugin-syntax-async-functions@^6.8.0:
   version "6.13.0"
   resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95"
@@ -1607,7 +1585,7 @@ babel-plugin-syntax-flow@^6.18.0:
   resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d"
   integrity sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=
 
-babel-plugin-syntax-jsx@^6.18.0, babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0:
+babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0:
   version "6.18.0"
   resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"
   integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=
@@ -2470,11 +2448,6 @@ camelcase@^5.3.1:
   resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
   integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
 
-camelize@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b"
-  integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=
-
 caniuse-api@^1.5.2:
   version "1.6.1"
   resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c"
@@ -2623,6 +2596,11 @@ class-utils@^0.3.5:
     isobject "^3.0.0"
     static-extend "^0.1.1"
 
+classnames@^2.2.6:
+  version "2.2.6"
+  resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
+  integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
+
 clean-css@4.2.x:
   version "4.2.1"
   resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17"
@@ -2690,6 +2668,11 @@ clone@^1.0.2:
   resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
   integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
 
+clone@^2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
+  integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
+
 co@^4.6.0:
   version "4.6.0"
   resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
@@ -3092,11 +3075,6 @@ crypto-random-string@^1.0.0:
   resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
   integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=
 
-css-color-keywords@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
-  integrity sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=
-
 css-color-names@0.0.4, css-color-names@^0.0.4:
   version "0.0.4"
   resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
@@ -3176,15 +3154,6 @@ css-selector-tokenizer@^0.7.0:
     fastparse "^1.1.1"
     regexpu-core "^1.0.0"
 
-css-to-react-native@^2.2.2:
-  version "2.3.2"
-  resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-2.3.2.tgz#e75e2f8f7aa385b4c3611c52b074b70a002f2e7d"
-  integrity sha512-VOFaeZA053BqvvvqIA8c9n0+9vFppVBAHCp6JgFTtTMU3Mzi+XnelJ9XC9ul3BqFzZyQ5N+H0SnwsWT2Ebchxw==
-  dependencies:
-    camelize "^1.0.0"
-    css-color-keywords "^1.0.0"
-    postcss-value-parser "^3.3.0"
-
 css-tree@1.0.0-alpha.37:
   version "1.0.0-alpha.37"
   resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22"
@@ -3782,7 +3751,7 @@ entities@^2.0.0:
   resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4"
   integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==
 
-errno@^0.1.3, errno@~0.1.7:
+errno@^0.1.1, errno@^0.1.3, errno@~0.1.7:
   version "0.1.7"
   resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
   integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==
@@ -5089,6 +5058,11 @@ ignore-walk@^3.0.1:
   dependencies:
     minimatch "^3.0.4"
 
+image-size@~0.5.0:
+  version "0.5.5"
+  resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c"
+  integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=
+
 import-cwd@^2.0.0, import-cwd@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"
@@ -5579,11 +5553,6 @@ is-utf8@^0.2.0:
   resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
   integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
 
-is-what@^3.3.1:
-  version "3.3.1"
-  resolved "https://registry.yarnpkg.com/is-what/-/is-what-3.3.1.tgz#79502181f40226e2d8c09226999db90ef7c1bcbe"
-  integrity sha512-seFn10yAXy+yJlTRO+8VfiafC+0QJanGLMPTBWLrJm/QPauuchy0UXh8B6H5o9VA8BAzk0iYievt6mNp6gfaqA==
-
 is-windows@^1.0.1, is-windows@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
@@ -6350,6 +6319,22 @@ left-pad@^1.3.0:
   resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e"
   integrity sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==
 
+less@^3.10.3:
+  version "3.10.3"
+  resolved "https://registry.yarnpkg.com/less/-/less-3.10.3.tgz#417a0975d5eeecc52cff4bcfa3c09d35781e6792"
+  integrity sha512-vz32vqfgmoxF1h3K4J+yKCtajH0PWmjkIFgbs5d78E/c/e+UQTnI+lWK+1eQRE95PXM2mC3rJlLSSP9VQHnaow==
+  dependencies:
+    clone "^2.1.2"
+  optionalDependencies:
+    errno "^0.1.1"
+    graceful-fs "^4.1.2"
+    image-size "~0.5.0"
+    mime "^1.4.1"
+    mkdirp "^0.5.0"
+    promise "^7.1.1"
+    request "^2.83.0"
+    source-map "~0.6.0"
+
 leven@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580"
@@ -6498,7 +6483,7 @@ lodash.uniqueid@^4.0.1:
   resolved "https://registry.yarnpkg.com/lodash.uniqueid/-/lodash.uniqueid-4.0.1.tgz#3268f26a7c88e4f4b1758d679271814e31fa5b26"
   integrity sha1-MmjyanyI5PSxdY1nknGBTjH6WyY=
 
-"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.3.0:
+"lodash@>=3.5 <5", lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.3.0:
   version "4.17.15"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
   integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
@@ -6627,11 +6612,6 @@ mem@^1.1.0:
   dependencies:
     mimic-fn "^1.0.0"
 
-memoize-one@^5.0.0:
-  version "5.1.1"
-  resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0"
-  integrity sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==
-
 memory-fs@^0.4.0, memory-fs@~0.4.1:
   version "0.4.1"
   resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
@@ -6656,13 +6636,6 @@ meow@^3.3.0, meow@^3.7.0:
     redent "^1.0.0"
     trim-newlines "^1.0.0"
 
-merge-anything@^2.2.4:
-  version "2.4.1"
-  resolved "https://registry.yarnpkg.com/merge-anything/-/merge-anything-2.4.1.tgz#e9bccaec1e49ec6cb5f77ca78c5770d1a35315e6"
-  integrity sha512-dYOIAl9GFCJNctSIHWOj9OJtarCjsD16P8ObCl6oxrujAG+kOvlwJuOD9/O9iYZ9aTi1RGpGTG9q9etIvuUikQ==
-  dependencies:
-    is-what "^3.3.1"
-
 merge-deep@^3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/merge-deep/-/merge-deep-3.0.2.tgz#f39fa100a4f1bd34ff29f7d2bf4508fbb8d83ad2"
@@ -8346,7 +8319,14 @@ promise@8.0.1:
   dependencies:
     asap "~2.0.3"
 
-prop-types@^15.5.4, prop-types@^15.6.2:
+promise@^7.1.1:
+  version "7.3.1"
+  resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
+  integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==
+  dependencies:
+    asap "~2.0.3"
+
+prop-types@^15.6.2:
   version "15.7.2"
   resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
   integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@@ -8555,7 +8535,7 @@ react-error-overlay@^4.0.1:
   resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-4.0.1.tgz#417addb0814a90f3a7082eacba7cee588d00da89"
   integrity sha512-xXUbDAZkU08aAkjtUvldqbvI04ogv+a1XdHxvYuHPYKIVk/42BIOD0zSKTHAWV4+gDy3yGm283z2072rA2gdtw==
 
-react-is@^16.6.0, react-is@^16.8.1:
+react-is@^16.8.1:
   version "16.11.0"
   resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.11.0.tgz#b85dfecd48ad1ce469ff558a882ca8e8313928fa"
   integrity sha512-gbBVYR2p8mnriqAwWx9LbuUrShnAuSCNnuPGyc7GJrMVQtPDAh8iLpv7FRuMPFb56KkaVZIYSz1PrjI9q0QPCw==
@@ -8888,7 +8868,7 @@ request-promise-native@^1.0.5:
     stealthy-require "^1.1.1"
     tough-cookie "^2.3.3"
 
-request@^2.79.0, request@^2.87.0:
+request@^2.79.0, request@^2.83.0, request@^2.87.0:
   version "2.88.0"
   resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
   integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
@@ -9804,25 +9784,6 @@ style-loader@0.19.0:
     loader-utils "^1.0.2"
     schema-utils "^0.3.0"
 
-styled-components@^4.4.1:
-  version "4.4.1"
-  resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-4.4.1.tgz#e0631e889f01db67df4de576fedaca463f05c2f2"
-  integrity sha512-RNqj14kYzw++6Sr38n7197xG33ipEOktGElty4I70IKzQF1jzaD1U4xQ+Ny/i03UUhHlC5NWEO+d8olRCDji6g==
-  dependencies:
-    "@babel/helper-module-imports" "^7.0.0"
-    "@babel/traverse" "^7.0.0"
-    "@emotion/is-prop-valid" "^0.8.1"
-    "@emotion/unitless" "^0.7.0"
-    babel-plugin-styled-components ">= 1"
-    css-to-react-native "^2.2.2"
-    memoize-one "^5.0.0"
-    merge-anything "^2.2.4"
-    prop-types "^15.5.4"
-    react-is "^16.6.0"
-    stylis "^3.5.0"
-    stylis-rule-sheet "^0.0.10"
-    supports-color "^5.5.0"
-
 stylehacks@^4.0.0:
   version "4.0.3"
   resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5"
@@ -9832,16 +9793,6 @@ stylehacks@^4.0.0:
     postcss "^7.0.0"
     postcss-selector-parser "^3.0.0"
 
-stylis-rule-sheet@^0.0.10:
-  version "0.0.10"
-  resolved "https://registry.yarnpkg.com/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz#44e64a2b076643f4b52e5ff71efc04d8c3c4a430"
-  integrity sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw==
-
-stylis@^3.5.0:
-  version "3.5.4"
-  resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.4.tgz#f665f25f5e299cf3d64654ab949a57c768b73fbe"
-  integrity sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q==
-
 subarg@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2"
@@ -9868,7 +9819,7 @@ supports-color@^4.2.1:
   dependencies:
     has-flag "^2.0.0"
 
-supports-color@^5.1.0, supports-color@^5.3.0, supports-color@^5.4.0, supports-color@^5.5.0:
+supports-color@^5.1.0, supports-color@^5.3.0, supports-color@^5.4.0:
   version "5.5.0"
   resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
   integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==