diff --git a/.gitignore b/.gitignore index c3a754f5b..8ba0c7fc5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ node_modules/ dist/ lib/ -.DS_STORE \ No newline at end of file +.DS_STORE +coverage +pages-build +client-dist \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..8e3e50e22 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,13 @@ +language: node_js + +sudo: false + +node_js: + - "8" + +script: + - npm install codecov -g + - npm run lint + - npm run test +after_success: + - codecov \ No newline at end of file diff --git a/README.md b/README.md index 346177e64..851ac6532 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,16 @@ # react-viewer -[![NPM version][npm-image]][npm-url] +[![NPM version][npm-image]][npm-url] [![](https://travis-ci.org/infeng/react-viewer.svg?branch=master)](https://travis-ci.org/infeng/react-viewer) [![codecov](https://codecov.io/gh/infeng/react-viewer/branch/master/graph/badge.svg)](https://codecov.io/gh/infeng/react-viewer) > react image viewer. ## Introduction -Because i can`t comfortable use [viewerjs](https://github.com/fengyuanchen/viewerjs) in react, so i create react-viewer to replace it. +Because I can`t be comfortable using [viewerjs](https://github.com/fengyuanchen/viewerjs) in react, so I created react-viewer to replace it. ## Installation +> react >= 16.8.0 | react-dom >= 16.8.0 + ```bash npm install react-viewer --save ``` @@ -18,32 +20,50 @@ npm install react-viewer --save ```javascript import * as React from 'react'; import Viewer from 'react-viewer'; -import 'react-viewer/dist/index.css'; - -class App extends React.Component { - constructor() { - super(); - - this.state = { - visible: false, - }; - } - - render() { - return ( -
- - { this.setState({ visible: false }); } } - images={[{src: '', alt: ''}]} - /> -
- ); - } + +function App() { + const [ visible, setVisible ] = React.useState(false); + + return ( +
+ + { setVisible(false); } } + images={[{src: '', alt: ''}]} + /> +
+ ); } ``` +## Server Side (NextJS) + +``` +import React, { FC } from 'react' +import dynamic from 'next/dynamic' + +const ReactViewer = dynamic( + () => import('react-viewer'), + { ssr: false } +) + +export const Viewer: FC = () => { + return ( + {}} + images={[{src: ''}]} + /> + ) +} + +export default Viewer +``` + +## Server Side rest.. +I'm sorry, ssr is not currently supported in `3.x`, it will be fixed in `4.0`. + ## Props | props | type | default | description | required | @@ -69,6 +89,22 @@ class App extends React.Component { | changeable | boolean | true | wheather to show change button | false | | customToolbar | (defaultToolbarConfigs: [ToolbarConfig](#toolbarconfig)[]) => ToolbarConfig[] | - | customer toolbar | false | | zoomSpeed | number | 0.05 | zoom speed | false | +| defaultSize | [ViewerImageSize](#viewerimagesize) | - | default image size | false | +| defaultImg | [viewerdefaultimg](#viewerimagesize) | - | if load img failed, show default img | false | +| disableKeyboardSupport | boolean | false | disable keyboard support | false | +| noResetZoomAfterChange | boolean | false | preserve zoom after image change | false | +| noLimitInitializationSize | boolean | false | no limit image initialization size | false | +| defaultScale | number | 1 | set default scale | false | +| onChange | (activeImage: [ImageDecorator](#imagedecorator), index: number) => void | - | callback when image change | false | +| loop | boolean | true | whether enable image loop | false | +| disableMouseZoom | boolean | false | whether disable mouse zoom | false | +| downloadInNewWindow | boolean | false | whether to download in a new window | false | +| className | string | - | customized CSS class | false | +| showTotal | boolean | true | whether to display the total number and range | false | +| totalName | string | 'of' | total image separator name | false | +| maxScale | number | - | maximum scaling | false | +| minScale | number | 0.1 | minimum scaling | false | +| exportFileName | string | 'exportFile' | customize download's filename | false | ### ImageDecorator @@ -77,6 +113,22 @@ class App extends React.Component { | src | string | - | image source | true | | alt | string | - | image description | false | | downloadUrl | string | - | image downlaod url | false | +| defaultSize | [ViewerImageSize](#viewerimagesize) | - | image size | false | + +### ViewerImageSize + +| props | type | default | description | required | +|-------------|--------------|---------|-----------------------------|----------| +| width | number | - | image width | true | +| height | number | - | image height | true | + +### ViewerDefaultImg + +| props | type | default | description | required | +|-------------|--------------|---------|-----------------------------|----------| +| src | number | - | image source | true | +| width | number | - | image width | false | +| height | number | - | image height | false | ### ToolbarConfig @@ -97,7 +149,6 @@ class App extends React.Component { - `Ctrl + ←`: Rotate left the image. - `Ctrl + →`: Rotate right the image. - ## License MIT diff --git a/demo/images/fork_me_ribbon.svg b/demo/images/fork_me_ribbon.svg deleted file mode 100644 index 1ac8033b5..000000000 --- a/demo/images/fork_me_ribbon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/demo/index.less b/demo/index.less index c05490400..46789b2d9 100644 --- a/demo/index.less +++ b/demo/index.less @@ -19,11 +19,6 @@ ul, li { background-color: #0074d9; } -.navbar-fixed-top { - position: fixed; - top: 0; -} - .img-fork { position: absolute; width: 130px; @@ -35,33 +30,44 @@ ul, li { padding-right: 15px; padding-left: 15px; margin-right: auto; - margin-left: auto; + margin-left: auto; + display: flex; + align-items: center; + height: 100%; } .navbar-brand { color: white; font-size: 2rem; - line-height: @navbarHeight; + margin-right: 24px; +} + +.bagde { + margin-left: 6px; + display: flex; + align-items: center; +} + +.github { + position: absolute; + right: 15px; } .container { - top: 50px; - padding: 2em; + padding: 1.5em 2em 2em 2em; } -.title { - font-size: 3rem; - font-weight: bold; - border-bottom: 1px solid #eee; - margin-bottom: 1.5rem; +.wrap { + display: flex; +} + +.img-list-wrap { + flex: 1; } .img-list { display: flex; - width: 640px; - height: 500px; - margin: 0 auto; - justify-content: center; + justify-content: flex-start; &.hide { display: none; @@ -101,14 +107,21 @@ ul, li { } .inline-container { display: none; - width: 600px; - height: 400px; - margin: 0 auto; + max-width: 600px; + // height: 400px; &.show { display: block; } } +.options { + margin-top: 12px; + width: 100%; + max-width: 250px; + margin-right: 48px; +} .options-list { margin-top: 12px; + height: 440px; + overflow: auto; } \ No newline at end of file diff --git a/demo/index.tsx b/demo/index.tsx index c2f7d6848..12e950993 100644 --- a/demo/index.tsx +++ b/demo/index.tsx @@ -5,29 +5,113 @@ const img2 = require('./images/landscape2.jpg'); const img = require('./images/landscape.jpg'); const img3 = require('./images/tibet-6.jpg'); const img4 = require('./images/image4.jpg'); -const forkImg = require('./images/fork_me_ribbon.svg'); import './index.less'; import classNames from 'classnames'; -import { Row, Col, Button } from 'antd'; +import { Button, List, Checkbox } from 'antd'; const ButtonGroup = Button.Group; interface State { visible: boolean; activeIndex: number; mode: 'modal' | 'inline'; + drawerVisible: boolean; + drag: boolean; + attribute: boolean; } +interface OptionData { + key: string; + type: 'boolean'; + value?: any; +} + +const optionData: OptionData[] = [{ + key: 'drag', + type: 'boolean', +}, { + key: 'attribute', + type: 'boolean', +}, { + key: 'zoomable', + type: 'boolean', +}, { + key: 'rotatable', + type: 'boolean', +}, { + key: 'scalable', + type: 'boolean', +}, { + key: 'downloadable', + type: 'boolean', +}, { + key: 'loop', + type: 'boolean', +}, { + key: 'noClose', + type: 'boolean', + value: false, +}, { + key: 'noImgDetails', + type: 'boolean', + value: false, +}, { + key: 'noNavbar', + type: 'boolean', + value: false, +}, { + key: 'noToolbar', + type: 'boolean', + value: false, +}, { + key: 'noFooter', + type: 'boolean', + value: false, +}, { + key: 'changeable', + type: 'boolean', +}, { + key: 'disableKeyboardSupport', + type: 'boolean', + value: false, +}, { + key: 'noResetZoomAfterChange', + type: 'boolean', + value: false, +}, { + key: 'noLimitInitializationSize', + type: 'boolean', + value: false, +}, { + key: 'disableMouseZoom', + type: 'boolean', + value: false, +}, { + key: 'downloadInNewWindow', + type: 'boolean', + value: false, +}, { + key: 'showTotal', + type: 'boolean', +}]; + class App extends React.Component> { container: HTMLDivElement; - constructor() { - super(); + constructor(props) { + super(props); this.state = { visible: false, activeIndex: 0, mode: 'modal', }; + optionData.forEach(item => { + if (item.value === undefined) { + this.state[item.key] = true; + } else { + this.state[item.key] = item.value; + } + }); } handleChangeModal = (e) => { @@ -43,6 +127,12 @@ class App extends React.Component> { }); } + handleOption = key => { + this.setState({ + [key]: !this.state[key], + }); + } + render() { let images = [{ src: img, @@ -72,24 +162,41 @@ class App extends React.Component> { hide: this.state.visible && inline, }); + let options = {}; + optionData.forEach(item => { + options[item.key] = this.state[item.key]; + }); + return (
-