[
  {
    "path": ".gitignore",
    "content": "/coverage\n/demo/dist\n/es\n/lib\n/node_modules\n/umd\nnpm-debug.log*\n.vscode/"
  },
  {
    "path": ".travis.yml",
    "content": "sudo: false\n\nlanguage: node_js\nnode_js:\n  - 8\n\nbefore_install:\n  - npm install codecov.io coveralls\n\nafter_success:\n  - cat ./coverage/lcov.info | ./node_modules/codecov.io/bin/codecov.io.js\n  - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js\n\nbranches:\n  only:\n    - master\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "## 0.9.8\n\n### Improvements\n\n- Add Type Definitions for Typescript (#12) (thanks @danilofuchs)\n- Add support for `children` property (#13) (thanks @federico-bohn)\n\n## 0.9.7\n\n### Fixes\n\n- [Interaction] Fix bug where point annotation would fail abort (#8) (thanks @joshuadeguzman)\n\n## 0.9.6\n\n### Breaking change\n\n- [Interaction] Change annotation click action to click and drag (#6)\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "## Prerequisites\n\n[Node.js](http://nodejs.org/) >= v4 must be installed.\n\n## Installation\n\n- Running `npm install` in the component's root directory will install everything you need for development.\n\n## Demo Development Server\n\n- `npm start` will run a development server with the component's demo app at [http://localhost:3000](http://localhost:3000) with hot module reloading.\n\n## Running Tests\n\n- `npm test` will run the tests once.\n\n- `npm run test:coverage` will run the tests and produce a coverage report in `coverage/`.\n\n- `npm run test:watch` will run the tests on every change.\n\n## Building\n\n- `npm run build` will build the component for publishing to npm and also bundle the demo app.\n\n- `npm run clean` will delete built resources.\n"
  },
  {
    "path": "LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2018-present, Arian Allenson Valdez.\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "React Image Annotation\n=========================\n\nAn infinitely customizable image annotation library built on React\n\n![Annotation demo](demo.gif)\n\n## Installation\n\n```\nnpm install --save react-image-annotation\n# or\nyarn add react-image-annotation\n```\n\n## Usage\n\n```js\nexport default class Simple extends Component {\n  state = {\n    annotations: [],\n    annotation: {}\n  }\n\n  onChange = (annotation) => {\n    this.setState({ annotation })\n  }\n\n  onSubmit = (annotation) => {\n    const { geometry, data } = annotation\n\n    this.setState({\n      annotation: {},\n      annotations: this.state.annotations.concat({\n        geometry,\n        data: {\n          ...data,\n          id: Math.random()\n        }\n      })\n    })\n  }\n\n  render () {\n    return (\n      <Root>\n        <Annotation\n          src={img}\n          alt='Two pebbles anthropomorphized holding hands'\n\n          annotations={this.state.annotations}\n\n          type={this.state.type}\n          value={this.state.annotation}\n          onChange={this.onChange}\n          onSubmit={this.onSubmit}\n        />\n      </Root>\n    )\n  }\n}\n```\n\n\n### Props\n\nProp | Description | Default\n---- | ----------- | -------\n`src` | Image src attribute |\n`alt` | Image alt attribute |\n`annotations` | Array of annotations |\n`value` | Annotation object currently being created. See [annotation object](#annotation-object)  |\n`onChange` | `onChange` handler for annotation object |\n`onSubmit` | `onSubmit` handler for annotation object |\n`type` | Selector type. See [custom shapes](#using-custom-shapes) | `RECTANGLE`\n`allowTouch` | Set to `true` to allow the target to handle touch events. This disables one-finger scrolling | `false`\n`selectors` | An array of selectors. See [adding custom selector logic](#adding-custom-selector-logic) | `[RectangleSelector, PointSelector, OvalSelector]`\n`activeAnnotations` | Array of annotations that will be passed as 'active' (active highlight and shows content) |\n`activeAnnotationComparator` | Method to compare annotation and `activeAnnotation` item (from `props.activeAnnotations`). Return `true` if it's the annotations are equal | `(a, b) => a === b`\n`disableAnnotation` | Set to `true` to disable creating of annotations (note that no callback methods will be called if this is `true`) | `false`\n`disableSelector` | Set to `true` to not render `Selector` | `false`\n`disableEditor` | Set to `true` to not render `Editor` | `false`\n`disableOverlay` | Set to `true` to not render `Overlay` | `false`\n`renderSelector` | Function that renders `Selector` Component | See [custom components](#using-custom-components)\n`renderEditor` | Function that renders `Editor` Component | See [custom components](#using-custom-components)\n`renderHighlight` | Function that renders `Highlight` Component | See [custom components](#using-custom-components)\n`renderContent` | Function that renders `Content` | See [custom components](#using-custom-components)\n`renderOverlay` | Function that renders `Overlay` | See [custom components](#using-custom-components)\n`onMouseUp` | `onMouseUp` handler on annotation target |\n`onMouseDown` | `onMouseDown` handler on annotation target |\n`onMouseMove` | `onMouseMove` handler on annotation target |\n`onClick` | `onClick` handler on annotation target |\n\n#### Annotation object\n\nAn Annotation object is an object that conforms to the object shape\n\n```js\n({\n  selection: T.object, // temporary object for selector logic\n  geometry: T.shape({ // geometry data for annotation\n    type: T.string.isRequired // type is used to resolve Highlighter/Selector renderer\n  }),\n  // auxiliary data object for application.\n  // Content data can be stored here (text, image, primary key, etc.)\n  data: T.object\n})\n```\n\n## Using custom components\n\n`Annotation` supports `renderProp`s for almost every internal component.\n\nThis allows you to customize everything about the the look of the annotation interface, and you can even use canvas elements for performance or more complex interaction models.\n\n- `renderSelector` - used for selecting annotation area (during annotation creation)\n- `renderEditor` - appears after annotation area has been selected (during annotation creation)\n- `renderHighlight` - used to render current annotations in the annotation interface. It is passed an object that contains the property `active`, which is true if the mouse is hovering over the higlight\n- `renderComponent` - auxiliary component that appears when mouse is hovering over the highlight. It is passed an object that contains the annotation being hovered over. `{ annotation }`\n- `renderOverlay` - Component overlay for Annotation (i.e. 'Click and Drag to Annotate')\n\nYou can view the default renderProps [here](src/components/defaultProps.js)\n\n**Note**: You cannot use `:hover` selectors in css for components returned by `renderSelector` and `renderHighlight`. This is due to the fact that `Annotation` places DOM layers on top of these components, preventing triggering of `:hover`\n\n## Using custom shapes\n\n`Annotation` supports three shapes by default, `RECTANGLE`, `POINT` and `OVAL`.\n\nYou can switch the shape selector by passing the appropriate `type` as a property. Default shape `TYPE`s are accessible on their appropriate selectors:\n\n```js\nimport {\n  PointSelector,\n  RectangleSelector,\n  OvalSelector\n} from 'react-image-annotation/lib/selectors'\n\n<Annotation\n  type={PointSelector.TYPE}\n/>\n```\n\n### Adding custom selector logic\n\n#### This is an Advanced Topic\n\nThe Annotation API allows support for custom shapes that use custom logic such as polygon or freehand selection. This is done by defining your own selection logic and passing it as a selector in the `selectors` property.\n\nSelectors are objects that must have the following properties:\n\n- `TYPE` - string that uniquely identifies this selector (i.e. `RECTANGLE`)\n- `intersects` - method that returns true if the mouse point intersects with the annotation geometry\n- `area` - method that calculates and returns the area of the annotation geometry\n- `methods` - object that can contain various listener handlers (`onMouseUp`, `onMouseDown`, `onMouseMove`, `onClick`). These listener handlers are called when triggered in the annotation area. These handlers must be reducer-like methods - returning a new annotation object depending on the change of the method\n\nYou can view a defined `RectangleSelector` [here](src/hocs/RectangleSelector.js)\n\n### Connecting selector logic to Redux/MobX\n\nFirst see [Selectors](#adding-custom-selector-logic)\n\nYou can use `Selector` methods to connect these method logic to your stores. This is due to the fact that selector methods function as reducers, returning new state depending on the event.\n\n***Note that it is not necessary to connect the selector logic with redux/mobx. Connecting the annotation and annotations state is more than enough for most use cases.***\n\n## License\n\nMIT\n"
  },
  {
    "path": "demo/public/404.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <title>Single Page Apps for GitHub Pages</title>\n    <script type=\"text/javascript\">\n      // Single Page Apps for GitHub Pages\n      // https://github.com/rafrex/spa-github-pages\n      // Copyright (c) 2016 Rafael Pedicini, licensed under the MIT License\n      // ----------------------------------------------------------------------\n      // This script takes the current url and converts the path and query\n      // string into just a query string, and then redirects the browser\n      // to the new url with only a query string and hash fragment,\n      // e.g. http://www.foo.tld/one/two?a=b&c=d#qwe, becomes\n      // http://www.foo.tld/?p=/one/two&q=a=b~and~c=d#qwe\n      // Note: this 404.html file must be at least 512 bytes for it to work\n      // with Internet Explorer (it is currently > 512 bytes)\n      // If you're creating a Project Pages site and NOT using a custom domain,\n      // then set segmentCount to 1 (enterprise users may need to set it to > 1).\n      // This way the code will only replace the route part of the path, and not\n      // the real directory in which the app resides, for example:\n      // https://username.github.io/repo-name/one/two?a=b&c=d#qwe becomes\n      // https://username.github.io/repo-name/?p=/one/two&q=a=b~and~c=d#qwe\n      // Otherwise, leave segmentCount as 0.\n      var segmentCount = 1;\n      var l = window.location;\n      l.replace(\n        l.protocol + '//' + l.hostname + (l.port ? ':' + l.port : '') +\n        l.pathname.split('/').slice(0, 1 + segmentCount).join('/') + '/?p=/' +\n        l.pathname.slice(1).split('/').slice(segmentCount).join('/').replace(/&/g, '~and~') +\n        (l.search ? '&q=' + l.search.slice(1).replace(/&/g, '~and~') : '') +\n        l.hash\n      );\n    </script>\n  </head>\n  <body>\n  </body>\n</html>\n"
  },
  {
    "path": "demo/src/App.js",
    "content": "import React from 'react'\nimport { BrowserRouter as Router, Route } from 'react-router-dom'\nimport styled from 'styled-components'\n\nimport NavBar from './components/NavBar'\nimport Root from './components/Root'\nimport Home from './components/Home'\nimport Docs from './components/Docs'\nimport Footer from './components/Footer'\n\nconst Main = styled.main`\n  margin: 0 16px;\n  margin-top: 51px;\n`\n\nexport default () => (\n  <Router basename='/react-image-annotation'>\n    <Root>\n      <NavBar\n        title='react-image-annotation'\n      />\n      <Main>\n        <Route\n          exact\n          path='/'\n          component={Home}\n        />\n        <Route\n          path='/docs'\n          component={Docs}\n        />\n      </Main>\n      <Footer />\n    </Root>\n  </Router>\n)\n"
  },
  {
    "path": "demo/src/components/Button/index.js",
    "content": "import styled, { css } from 'styled-components'\nimport { Link } from 'react-router-dom'\n\nconst styles = css`\n  background: #24B3C8;\n  border: 0;\n  color: white;\n  cursor: pointer;\n  font-family: Montserrat;\n  font-size: 13px;\n  font-weight: 700;\n  outline: 0;\n  margin: 4px;\n  padding: 8px 16px;\n  text-shadow: 0 1px 0 rgba(0,0,0,0.1);\n  text-transform: uppercase;\n\n  transition: background 0.21s ease-in-out;\n\n  &:focus, &:hover {\n    background: #176572;\n  }\n\n  ${props => props.active && `\n    background: #176572;\n  `}\n`\n\nexport default styled.button`\n  ${props => styles}\n`\n\nexport const ButtonLink = styled(Link)`\n  text-decoration: none;\n  ${props => styles}\n`\n"
  },
  {
    "path": "demo/src/components/Docs/index.js",
    "content": "import React, { Component } from 'react'\nimport styled from 'styled-components'\nimport Highlight from '../Highlight'\nimport Multi from '../Samples/Multiple'\nimport multiCode from '../Samples/Multiple/index.txt'\nimport Linked from '../Samples/Linked'\nimport linkedCode from '../Samples/Linked/index.txt'\nimport Custom from '../Samples/Custom'\nimport Threaded from '../Samples/Threaded'\nimport Touch from '../Samples/Touch'\nimport touchCode from '../Samples/Touch/index.txt'\n\nconst Container = styled.main`\n  margin: 0 auto;\n  padding-top: 16px;\n  padding-bottom: 64px;\n  max-width: 700px;\n`\n\nconst SourceLink = styled.a`\n  display: block;\n  margin-top: 8px;\n  font-size: 18px;\n  text-align: center;\n  text-decoration: none;\n`\n\nexport default class Docs extends Component {\n  render () {\n    return (\n      <Container>\n        <h1>Multiple Type/Shape Support</h1>\n        <Multi />\n        <Highlight>\n          {multiCode}\n        </Highlight>\n        <h1>Controlled Active Annotations</h1>\n        <Linked />\n        <p>Hover over the text items above and notice how it triggers the active status of their respective annotations</p>\n        <Highlight>\n          {linkedCode}\n        </Highlight>\n        <h1>Custom Renderers/Components/Styles</h1>\n        <Custom />\n        <SourceLink target='_blank' href='https://github.com/Secretmapper/react-image-annotation/blob/master/demo/src/components/Samples/Custom/index.js'>\n          View source\n        </SourceLink>\n        <h1>Threaded Comments (Custom Content Overlay)</h1>\n        <Threaded />\n        <SourceLink target='_blank' href='https://github.com/Secretmapper/react-image-annotation/blob/master/demo/src/components/Samples/Threaded/index.js'>\n          View source\n        </SourceLink>\n        <h1>Touch support</h1>\n        <Touch />\n        <Highlight>\n          {touchCode}\n        </Highlight>\n      </Container>\n    )\n  }\n}\n"
  },
  {
    "path": "demo/src/components/Footer/index.js",
    "content": "import React from 'react'\nimport styled from 'styled-components'\n\nconst Footer = styled.div`\n  color: #666;\n  padding: 16px;\n  padding-bottom: 32px;\n  text-align: center;\n  a {\n    color: inherit;\n    text-decoration: none;\n    &:hover {\n      color: #222;\n    }\n  }\n`\n\nexport default () => (\n  <Footer>\n    <p>\n      {'Made with <3 by '}\n      <a href='//arianv.com'>@secretmapper</a>\n    </p>\n  <p>\n    Released under the MIT License\n  </p>\n  </Footer>\n)\n"
  },
  {
    "path": "demo/src/components/GithubStarLink/index.js",
    "content": "import React from 'react'\n\nexport default () => (\n  <a\n    className='github-button'\n    href='https://github.com/Secretmapper/react-image-annotation'\n    data-size='large'\n    data-show-count\n    aria-label='Star Secretmapper/react-image-annotation on GitHub'\n  >\n    Star\n  </a>\n)\n"
  },
  {
    "path": "demo/src/components/Highlight/index.js",
    "content": "import React from 'react'\nimport SyntaxHighlighter from 'react-syntax-highlighter/prism-light'\nimport prism from 'react-syntax-highlighter/styles/prism/prism'\n\nexport default (props) => (\n  <SyntaxHighlighter language='jsx' style={prism}>\n    {props.children}\n  </SyntaxHighlighter>  \n)\n"
  },
  {
    "path": "demo/src/components/Home/index.js",
    "content": "import React, { Component } from 'react'\nimport styled from 'styled-components'\nimport Simple from '../Samples/Simple'\nimport Highlight from '../Highlight'\nimport GithubStarLink from '../GithubStarLink'\nimport { ButtonLink } from '../Button'\n\nimport simple from './simple.txt'\n\nconst Hero = styled.div`\n  text-align: center;\n`\n\nconst Title = styled.h1`\n  font-size: 36px;\n  text-align: center;\n`\n\nconst Subtitle = styled.p`\n  font-size: 20px;\n  text-align: center;\n`\n\nconst Container = styled.main`\n  margin: 0 auto;\n  padding: 64px 0;\n  max-width: 700px;\n`\n\nconst GithubButton = styled.div`\n  margin-bottom: 16px;\n`\n\nexport default class App extends Component {\n  render () {\n    return (\n      <Container>\n        <Hero>\n          <Title>React Image Annotation</Title>\n          <Subtitle>\n            An infinitely customizable image annotation library built on React\n          </Subtitle>\n          <GithubButton>\n            <GithubStarLink />\n          </GithubButton>\n          <ButtonLink to='/docs'>\n            More Examples\n          </ButtonLink>\n        </Hero>\n        <h2>Install</h2>\n        <Highlight>\n          npm install --save react-image-annotation\n        </Highlight>\n        <h2>Demo</h2>\n        <Simple />\n        <Highlight>\n          {simple}\n        </Highlight>  \n      </Container>\n    )\n  }\n}\n"
  },
  {
    "path": "demo/src/components/Home/simple.txt",
    "content": "import React, { Component } from 'react'\nimport Annotation from 'react-image-annotation'\n\nexport default class Simple extends Component {\n  state = {\n    annotations: [],\n    annotation: {}\n  }\n\n  onChange = (annotation) => {\n    this.setState({ annotation })\n  }\n\n  onSubmit = (annotation) => {\n    const { geometry, data } = annotation\n\n    this.setState({\n      annotation: {},\n      annotations: this.state.annotations.concat({\n        geometry,\n        data: {\n          ...data,\n          id: Math.random()\n        }\n      })\n    })\n  }\n\n  render () {\n    return (\n      <Annotation\n        src={IMAGE_URL}\n        alt='Two pebbles anthropomorphized holding hands'\n\n        annotations={this.state.annotations}\n\n        type={this.state.type}\n        value={this.state.annotation}\n        onChange={this.onChange}\n        onSubmit={this.onSubmit}\n        allowTouch\n      />\n    )\n  }\n}\n"
  },
  {
    "path": "demo/src/components/NavBar/index.js",
    "content": "import React from 'react'\nimport styled from 'styled-components'\nimport { Link } from 'react-router-dom'\n\nconst Header = styled.header`\n  background-color: #fcfcfc;\n  box-shadow: 0 0 4px rgba(0, 0, 0, 0.25);\n  box-sizing: border-box;\n  width: 100%;\n\n  position: fixed;\n  top: 0;\n  left: 0;\n  right: 0;\n  z-index: 100;\n`\n\nconst Items = styled.div`\n  margin: 0 auto;\n  max-width: 720px;\n  display: table;\n`\n\nconst Item = styled.div`\n  display: table-cell;\n  padding: 16px 0;\n  ${props => props.grow && `\n    width: 100%;\n  `}\n\n  a {\n    color: black;\n    text-decoration: none;\n    padding: 16px;\n\n    transition:\n      background 0.1s ease,\n      color 0.21s ease;\n    &:hover {\n      background: #dadada;\n      color: white;\n    }\n  }\n`\n\nconst Title = styled(Link)`\n  margin-right: 16px;\n`\n\nexport default (props) => (\n  <Header>\n    <Items>\n      <Item grow>\n        <Title to='/'>\n          {props.title}\n        </Title>\n        <Link to='/docs'>Docs</Link>\n      </Item>\n      <Item>\n        <a href='//github.com/Secretmapper/react-image-annotation' target='__blank'>\n          Github\n        </a>\n      </Item>\n    </Items>\n  </Header>\n)\n"
  },
  {
    "path": "demo/src/components/Root/index.js",
    "content": "import styled from 'styled-components'\n\nexport default styled.div`\n  font-family: 'Open Sans', sans-serif;\n  margin: 0 auto;\n  font-size: 14px;\n\n  h1, h2, h3, h4, h5, h6 {\n    font-family: 'Montserrat', sans-serif;\n  }\n\n  input {\n    font-family: 'Open Sans', sans-serif;\n  }\n`\n"
  },
  {
    "path": "demo/src/components/Samples/Custom/index.js",
    "content": "import React, { Component } from 'react'\nimport Annotation from '../../../../../src'\nimport {\n  PointSelector,\n  RectangleSelector,\n  OvalSelector\n} from '../../../../../src/selectors'\n\nimport Button from '../../Button'\n\nimport mocks from '../../../mocks'\nimport img from '../../../img.jpeg'\n\nconst Box = ({ children, geometry, style }) => (\n  <div\n    style={{\n      ...style,\n      position: 'absolute',\n      left: `${geometry.x}%`,\n      top: `${geometry.y}%`,\n      height: `${geometry.height}%`,\n      width: `${geometry.width}%`,\n    }}\n  >\n    {children}\n  </div>\n)\n\nfunction renderSelector ({ annotation, active }) {\n  const { geometry } = annotation\n  if (!geometry) return null\n\n  return (\n    <Box\n      geometry={geometry}\n      style={{\n        background: 'rgba(255, 255, 255, 0.5)',\n        border: 'solid 1px red'\n      }}\n    >\n      Custom Selector\n    </Box>\n  )\n}\n\nfunction renderHighlight ({ annotation, active }) {\n  const { geometry } = annotation\n  if (!geometry) return null\n\n  return (\n    <Box\n      key={annotation.data.id}\n      geometry={geometry}\n      style={{\n        border: 'solid 1px black',\n        boxShadow: active\n          && '0 0 20px 20px rgba(255, 255, 255, 0.3) inset'\n      }}\n    >\n      Custom Highlight\n    </Box>\n  )\n}\n\nfunction renderContent ({ annotation }) {\n  const { geometry } = annotation\n  return (\n    <div\n      key={annotation.data.id}\n      style={{\n        background: 'black',\n        color: 'white',\n        padding: 10,\n        position: 'absolute',\n        fontSize: 12,\n        left: `${geometry.x}%`,\n        top: `${geometry.y + geometry.height}%`\n      }}\n    >\n      <div>Custom Content</div>\n      {annotation.data && annotation.data.text}\n    </div>\n  )\n}\n\nfunction renderEditor (props) {\n  const { geometry } = props.annotation\n  if (!geometry) return null\n\n  return (\n    <div\n      style={{\n        background: 'white',\n        borderRadius: 3,\n        position: 'absolute',\n        left: `${geometry.x}%`,\n        top: `${geometry.y + geometry.height}%`,\n      }}\n    >\n      <div>Custom Editor</div>\n      <input\n        onChange={e => props.onChange({\n          ...props.annotation,\n          data: {\n            ...props.annotation.data,\n            text: e.target.value\n          }\n        })}\n      />\n      <button onClick={props.onSubmit}>Comment</button>\n    </div>\n  )\n}\n\nfunction renderOverlay () {\n  return (\n    <div\n      style={{\n        background: 'rgba(0, 0, 0, 0.3)',\n        color: 'white',\n        padding: 5,\n        pointerEvents: 'none',\n        position: 'absolute',\n        top: 5,\n        left: 5\n      }}\n    >\n      Custom Overlay\n    </div>\n  )\n}\n\nexport default class Custom extends Component {\n  state = {\n    annotations: [mocks.annotations[0]],\n    annotation: {}\n  }\n\n  onChange = (annotation) => {\n    this.setState({ annotation })\n  }\n\n  onSubmit = (annotation) => {\n    const { geometry, data } = annotation\n\n    this.setState({\n      annotation: {},\n      annotations: this.state.annotations.concat({\n        geometry,\n        data: {\n          ...data,\n          id: Math.random()\n        }\n      })\n    })\n  }\n\n  onChangeType = (e) => {\n    this.setState({\n      annotation: {},\n      type: e.currentTarget.innerHTML\n    })\n  }\n\n  render () {\n    return (\n      <div>\n        <Annotation\n          src={img}\n          alt='Two pebbles anthropomorphized holding hands'\n\n          annotations={this.state.annotations}\n\n          type={this.state.type}\n          value={this.state.annotation}\n          onChange={this.onChange}\n          onSubmit={this.onSubmit}\n          renderSelector={renderSelector}\n          renderEditor={renderEditor}\n          renderHighlight={renderHighlight}\n          renderContent={renderContent}\n          renderOverlay={renderOverlay}\n        />\n      </div>\n    )\n  }\n}\n"
  },
  {
    "path": "demo/src/components/Samples/Linked/index.js",
    "content": "import React, { Component } from 'react'\nimport styled from 'styled-components'\nimport Annotation from '../../../../../src'\n\nimport Root from '../../Root'\nimport img from '../../../img.jpeg'\n\nconst Comments = styled.div`\n  border: 1px solid black;\n  max-height: 80px;\n  overflow: auto;\n`\n\nconst Comment = styled.div`\n  padding: 8px;\n\n  &:nth-child(even) {\n    background: rgba(0, 0, 0, .05);\n  }\n  &:hover {\n    background: #ececec;\n  }\n`\n\nexport default class Linked extends Component {\n  state = {\n    activeAnnotations: [],\n    annotations: [\n      {\n        data: {text: 'Hello!', id: 0.5986265691759928},\n        geometry: {type: 'RECTANGLE', x: 25.571428571428573, y: 33, width: 21.142857142857142, height: 34}\n      },\n      {\n        data: {text: 'Hi!', id: 0.5986265691759929},\n        geometry: {type: 'RECTANGLE', x: 50.571428571428573, y: 33, width: 21.142857142857142, height: 34}\n      }\n    ],\n    annotation: {}\n  }\n\n  onChange = (annotation) => {\n    this.setState({ annotation })\n  }\n\n  onSubmit = (annotation) => {\n    const { geometry, data } = annotation\n\n    this.setState({\n      annotation: {},\n      annotations: this.state.annotations.concat({\n        geometry,\n        data: {\n          ...data,\n          id: Math.random()\n        }\n      })\n    })\n  }\n\n  onMouseOver = (id) => e => {\n    this.setState({\n      activeAnnotations: [\n        ...this.state.activeAnnotations,\n        id\n      ]\n    })\n  }\n\n  onMouseOut = (id) => e => {\n    const index = this.state.activeAnnotations.indexOf(id)\n\n    this.setState({\n      activeAnnotations: [\n        ...this.state.activeAnnotations.slice(0, index),\n        ...this.state.activeAnnotations.slice(index + 1)\n      ]\n    })\n  }\n\n  activeAnnotationComparator = (a, b) => {\n    return a.data.id === b\n  }\n\n  render () {\n    return (\n      <Root>\n        <Annotation\n          src={img}\n          alt='Two pebbles anthropomorphized holding hands'\n\n          activeAnnotationComparator={this.activeAnnotationComparator}\n          activeAnnotations={this.state.activeAnnotations}\n          annotations={this.state.annotations}\n\n          type={this.state.type}\n          value={this.state.annotation}\n          onChange={this.onChange}\n          onSubmit={this.onSubmit}\n        />\n        <h4>Annotations</h4>\n        <Comments>\n          {this.state.annotations.map(annotation => (\n            <Comment\n              onMouseOver={this.onMouseOver(annotation.data.id)}\n              onMouseOut={this.onMouseOut(annotation.data.id)}\n              key={annotation.data.id}\n            >\n              {annotation.data.text}\n            </Comment>\n          ))}\n        </Comments>\n      </Root>\n    )\n  }\n}\n"
  },
  {
    "path": "demo/src/components/Samples/Linked/index.txt",
    "content": "classs React extends Component {\n  state = {\n    activeAnnotations: []\n  }\n\n  // ...other React code\n\n  onMouseOver = (id) => e => {\n    this.setState({\n      activeAnnotations: [\n        ...this.state.activeAnnotations,\n        id\n      ]\n    })\n  }\n\n  onMouseOut = (id) => e => {\n    const index = this.state.activeAnnotations.indexOf(id)\n\n    this.setState({\n      activeAnnotations: [\n        ...this.state.activeAnnotations.slice(0, index),\n        ...this.state.activeAnnotations.slice(index + 1)\n      ]\n    })\n  }\n\n  activeAnnotationComparator = (a, b) => {\n    return a.data.id === b\n  }\n\n  render () {\n    return (\n      <Root>\n        <Annotation\n          activeAnnotationComparator={this.activeAnnotationComparator}\n          activeAnnotations={this.state.activeAnnotations}\n          {//other props}\n        />\n        <h4>Annotations</h4>\n        <Comments>\n          {this.state.annotations.map(annotation => (\n            <Comment\n              onMouseOver={this.onMouseOver(annotation.data.id)}\n              onMouseOut={this.onMouseOut(annotation.data.id)}\n              key={annotation.data.id}\n            >\n              {annotation.data.text}\n            </Comment>\n          ))}\n        </Comments>\n      </Root>\n    )\n  }\n"
  },
  {
    "path": "demo/src/components/Samples/Multiple/index.js",
    "content": "import React, { Component } from 'react'\nimport Annotation from '../../../../../src'\nimport {\n  PointSelector,\n  RectangleSelector,\n  OvalSelector\n} from '../../../../../src/selectors'\n\nimport Button from '../../Button'\n\nimport mocks from '../../../mocks'\nimport img from '../../../img.jpeg'\n\nexport default class Multiple extends Component {\n  state = {\n    type: RectangleSelector.TYPE,\n    annotations: mocks.annotations,\n    annotation: {}\n  }\n\n  onChange = (annotation) => {\n    this.setState({ annotation })\n  }\n\n  onSubmit = (annotation) => {\n    const { geometry, data } = annotation\n\n    this.setState({\n      annotation: {},\n      annotations: this.state.annotations.concat({\n        geometry,\n        data: {\n          ...data,\n          id: Math.random()\n        }\n      })\n    })\n  }\n\n  onChangeType = (e) => {\n    this.setState({\n      annotation: {},\n      type: e.currentTarget.innerHTML\n    })\n  }\n\n  render () {\n    return (\n      <div>\n        <Button\n          onClick={this.onChangeType}\n          active={RectangleSelector.TYPE === this.state.type}\n        >\n          {RectangleSelector.TYPE}\n        </Button>\n        <Button\n          onClick={this.onChangeType}\n          active={PointSelector.TYPE === this.state.type}\n        >\n          {PointSelector.TYPE}\n        </Button>\n        <Button\n          onClick={this.onChangeType}\n          active={OvalSelector.TYPE === this.state.type}\n        >\n          {OvalSelector.TYPE}\n        </Button>\n\n        <Annotation\n          src={img}\n          alt='Two pebbles anthropomorphized holding hands'\n\n          annotations={this.state.annotations}\n\n          type={this.state.type}\n          value={this.state.annotation}\n          onChange={this.onChange}\n          onSubmit={this.onSubmit}\n        />\n      </div>\n    )\n  }\n}\n"
  },
  {
    "path": "demo/src/components/Samples/Multiple/index.txt",
    "content": "import React, { Component } from 'react'\nimport Annotation from 'react-image-annotation'\nimport {\n  PointSelector,\n  RectangleSelector,\n  OvalSelector\n} from 'react-image-annotation/lib/selectors'\n\nexport default class Multiple extends Component {\n  state = {\n    type: RectangleSelector.TYPE,\n    annotations: mocks.annotations,\n    annotation: {}\n  }\n\n  onChange = (annotation) => {\n    this.setState({ annotation })\n  }\n\n  onSubmit = (annotation) => {\n    const { geometry, data } = annotation\n\n    this.setState({\n      annotation: {},\n      annotations: this.state.annotations.concat({\n        geometry,\n        data: {\n          ...data,\n          id: Math.random()\n        }\n      })\n    })\n  }\n\n  onChangeType = (e) => {\n    this.setState({\n      annotation: {},\n      type: e.currentTarget.innerHTML\n    })\n  }\n\n  render () {\n    return (\n      <div>\n        <Button onClick={this.onChangeType}>\n          {RectangleSelector.TYPE}\n        </Button>\n        <Button onClick={this.onChangeType}>\n          {PointSelector.TYPE}\n        </Button>\n        <Button onClick={this.onChangeType}>\n          {OvalSelector.TYPE}\n        </Button>\n\n        <Annotation\n          src={img}\n          alt='Two pebbles anthropomorphized holding hands'\n\n          annotations={this.state.annotations}\n\n          type={this.state.type}\n          value={this.state.annotation}\n          onChange={this.onChange}\n          onSubmit={this.onSubmit}\n        />\n      </div>\n    )\n  }\n}\n"
  },
  {
    "path": "demo/src/components/Samples/Simple/index.js",
    "content": "import React, { Component } from 'react'\nimport Annotation from '../../../../../src'\n\nimport Root from '../../Root'\nimport img from '../../../img.jpeg'\n\nexport default class Simple extends Component {\n  state = {\n    annotations: [],\n    annotation: {}\n  }\n\n  onChange = (annotation) => {\n    this.setState({ annotation })\n  }\n\n  onSubmit = (annotation) => {\n    const { geometry, data } = annotation\n\n    this.setState({\n      annotation: {},\n      annotations: this.state.annotations.concat({\n        geometry,\n        data: {\n          ...data,\n          id: Math.random()\n        }\n      })\n    })\n  }\n\n  render () {\n    return (\n      <Root>\n        <Annotation\n          src={img}\n          alt='Two pebbles anthropomorphized holding hands'\n\n          annotations={this.state.annotations}\n\n          type={this.state.type}\n          value={this.state.annotation}\n          onChange={this.onChange}\n          onSubmit={this.onSubmit}\n          allowTouch\n        />\n      </Root>\n    )\n  }\n}\n"
  },
  {
    "path": "demo/src/components/Samples/Threaded/index.js",
    "content": "import React, { Component } from 'react'\nimport Annotation from '../../../../../src'\n\nimport styled, { keyframes } from 'styled-components'\nimport {\n  RectangleSelector\n} from '../../../../../src/selectors'\nimport TextEditor from '../../../../../src/components/TextEditor'\nimport Root from '../../Root'\nimport img from '../../../img.jpeg'\n\n/*\n * You would normally have the different components here\n * split into different files but I am\n * putting it in one file so it's easier to skim\n */\n\nconst Content = styled.div`\n  background: white;\n  border-radius: 2px;\n  box-shadow:\n    0px 1px 5px 0px rgba(0, 0, 0, 0.2),\n    0px 2px 2px 0px rgba(0, 0, 0, 0.14),\n    0px 3px 1px -2px rgba(0, 0, 0, 0.12);\n  margin: 8px 0;\n`\n\nconst ContentClearanceTop = styled.div`\n  position: absolute;\n  height: 8px;\n  top: -8px;\n  left: -17px;\n  right: -17px;\n`\n\nconst ContentClearanceLeft = styled.div`\n  position: absolute;\n  height: 100%;\n  left: -17px;\n  width: 20px;\n`\n\nconst ContentClearanceRight = styled.div`\n  position: absolute;\n  height: 100%;\n  right: 0px;\n  width: 20px;\n`\n\nconst fadeInScale = keyframes`\n  from {\n    opacity: 0;\n    transform: scale(0);\n  }\n\n  to {\n    opacity: 1;\n    transform: scale(1);\n  }\n`\n\nconst EditorContainer = styled.div`\n  background: white;\n  border-radius: 2px;\n  box-shadow:\n    0px 1px 5px 0px rgba(0, 0, 0, 0.2),\n    0px 2px 2px 0px rgba(0, 0, 0, 0.14),\n    0px 3px 1px -2px rgba(0, 0, 0, 0.12);\n  margin-top: 16px;\n  transform-origin: top left;\n\n  animation: ${fadeInScale} 0.31s cubic-bezier(0.175, 0.885, 0.32, 1.275);\n  overflow: hidden;\n`\n\nconst Comment = styled.div`\n  border-bottom: 1px solid whitesmoke;\n  padding: 8px 16px;\n`\n\nconst CommentDescription = styled.div`\n  margin: 10px 0;\n`\n\nconst UserPill = styled.span`\n  background-color: #2FB3C6;\n  border-radius: 4px;\n  color: white;\n  padding: 2px 4px;\n  font-size: 13.5px;\n`\n\nclass ThreadedEditor extends Component {\n  state = { text: '' }\n\n  onUpdateText = (e) => {\n    const { props } = this\n\n    // This is the purest (native es6) way to do this\n    // You can use a library such as redux and/or\n    // lodash/ramda to make this cleaner\n    props.onChange({\n      ...props.annotation,\n      data: {\n        ...props.annotation.data,\n        comments: [\n          this.props.annotation.data\n          ? {\n            ...this.props.annotation.data.comments[0],\n            text: e.target.value\n          }\n          : {\n            id: Math.random(),\n            text: e.target.value\n          }\n        ]\n      }\n    })\n  }\n\n  render () {\n    const { props } = this\n    const { geometry } = props.annotation\n    if (!geometry) return null\n\n    return (\n      <EditorContainer\n        className={props.className}\n        style={{\n          position: 'absolute',\n          left: `${geometry.x}%`,\n          top: `${geometry.y + geometry.height}%`,\n          ...props.style\n        }}\n      >\n        <TextEditor\n          onChange={this.onUpdateText}\n          onSubmit={props.onSubmit}\n          value={\n            props.annotation.data\n              ? props.annotation.data.comments[0].text\n              : ''\n          }\n        />\n      </EditorContainer>\n    )\n  }\n}\n\nclass ThreadedContent extends Component {\n  state = {\n    editorText: ''\n  }\n\n  onUpdateEditorText = (e) => {\n    this.setState({ editorText: e.target.value })\n  }\n\n  renderComment (comment) {\n    return (\n      <Comment key={comment.id}>\n        {comment.text}\n        <CommentDescription>\n          <UserPill>User</UserPill>\n        </CommentDescription>\n      </Comment>\n    )\n  }\n\n  render () {\n    const { props } = this\n    const { annotation } = props\n    const { geometry } = annotation\n    const comments = annotation.data && annotation.data.comments\n\n    return (\n      <React.Fragment>\n        <Content\n          key={props.annotation.data.id}\n          style={{\n            position: 'absolute',\n            left: `${geometry.x}%`,\n            top: `${geometry.y + geometry.height}%`\n          }}\n        >\n          <ContentClearanceTop />\n          <ContentClearanceLeft />\n          <ContentClearanceRight />\n          {(comments) && comments.map(this.renderComment)}\n          <TextEditor\n            value={this.state.editorText}\n            onChange={this.onUpdateEditorText}\n            onBlur={props.onBlur}\n            onFocus={props.onFocus}\n            onSubmit={e => {\n              const annotationIndex = props.annotations.indexOf(annotation)\n              const annotations = props.annotations.map((annotation, i) => (\n                i === annotationIndex\n                  ? {\n                    ...annotation,\n                    data: {\n                      ...annotation.data,\n                      comments: [\n                        ...comments,\n                        { id: Math.random(), text: this.state.editorText }\n                      ]\n                    }\n                  }\n                  : annotation\n              ))\n\n              this.setState({ editorText: '' })\n              props.setAnnotations(annotations)\n            }}\n          />\n        </Content>\n      </React.Fragment>\n    )\n  }\n}\n\nexport default class Threaded extends Component {\n  state = {\n    activeAnnotations: [],\n    annotations: [],\n    annotation: {}\n  }\n\n  onChange = (annotation) => {\n    this.setState({ annotation })\n  }\n\n  onSubmit = (annotation) => {\n    const { geometry, data } = annotation\n\n    this.setState({\n      annotation: {},\n      annotations: this.state.annotations.concat({\n        geometry,\n        data: {\n          ...data,\n          id: Math.random()\n        }\n      })\n    })\n  }\n\n  renderEditor = (props) => {\n    const { geometry } = props.annotation\n    if (!geometry) return null\n\n    return (\n      <ThreadedEditor {...props} />\n    )\n  }\n\n  renderContent = ({ key, annotation }) => {\n    return (\n      <ThreadedContent\n        key={key}\n        annotation={annotation}\n        annotations={this.state.annotations}\n        setAnnotations={annotations => this.setState({ annotations })}\n        onFocus={this.onFocus(key)}\n        onBlur={this.onBlur(key)}\n      />\n    )\n  }\n\n  onFocus = (id) => e => {\n    this.setState({\n      activeAnnotations: [\n        ...this.state.activeAnnotations,\n        id\n      ]\n    })\n  }\n\n  onBlur = (id) => e => {\n    const index = this.state.activeAnnotations.indexOf(id)\n\n    this.setState({\n      activeAnnotations: [\n        ...this.state.activeAnnotations.slice(0, index),\n        ...this.state.activeAnnotations.slice(index + 1)\n      ]\n    })\n  }\n\n  activeAnnotationComparator = (a, b) => {\n    return a.data.id === b\n  }\n\n  render () {\n    return (\n      <Root>\n        <Annotation\n          src={img}\n          alt='Two pebbles anthropomorphized holding hands'\n\n          activeAnnotationComparator={this.activeAnnotationComparator}\n          activeAnnotations={this.state.activeAnnotations}\n          annotations={this.state.annotations}\n\n          type={this.state.type}\n          value={this.state.annotation}\n          renderEditor={this.renderEditor}\n          renderContent={this.renderContent}\n          onChange={this.onChange}\n          onSubmit={this.onSubmit}\n        />\n      </Root>\n    )\n  }\n}\n"
  },
  {
    "path": "demo/src/components/Samples/Touch/index.js",
    "content": "import React, { Component } from 'react'\nimport Annotation from '../../../../../src'\nimport {\n  PointSelector,\n  RectangleSelector,\n  OvalSelector\n} from '../../../../../src/selectors'\n\nimport Button from '../../Button'\n\nimport mocks from '../../../mocks'\nimport img from '../../../img.jpeg'\n\nexport default class Multiple extends Component {\n  state = {\n    type: RectangleSelector.TYPE,\n    annotations: mocks.annotations,\n    annotation: {},\n    allowTouch: true\n  }\n\n  onChange = annotation => {\n    this.setState({ annotation })\n  }\n\n  onSubmit = annotation => {\n    const { geometry, data } = annotation\n\n    this.setState({\n      annotation: {},\n      annotations: this.state.annotations.concat({\n        geometry,\n        data: {\n          ...data,\n          id: Math.random()\n        }\n      })\n    })\n  }\n\n  onChangeType = e => {\n    this.setState({\n      annotation: {},\n      type: e.currentTarget.innerHTML\n    })\n  }\n\n  toggleAllowTouch = () => {\n    this.setState(prevState => ({ allowTouch: !prevState.allowTouch }))\n  }\n\n  render() {\n    return (\n      <div>\n        <div>\n          <Button onClick={this.toggleAllowTouch}>\n            {this.state.allowTouch\n              ? 'Stop allowing touch'\n              : 'Start allowing touch'}\n          </Button>\n        </div>\n        <div>\n          <Button\n            onClick={this.onChangeType}\n            active={RectangleSelector.TYPE === this.state.type}\n          >\n            {RectangleSelector.TYPE}\n          </Button>\n          <Button\n            onClick={this.onChangeType}\n            active={PointSelector.TYPE === this.state.type}\n          >\n            {PointSelector.TYPE}\n          </Button>\n\n          <Button\n            onClick={this.onChangeType}\n            active={OvalSelector.TYPE === this.state.type}\n          >\n            {OvalSelector.TYPE}\n          </Button>\n        </div>\n        <Annotation\n          src={img}\n          alt=\"Two pebbles anthropomorphized holding hands\"\n          annotations={this.state.annotations}\n          allowTouch={this.state.allowTouch}\n          type={this.state.type}\n          value={this.state.annotation}\n          onChange={this.onChange}\n          onSubmit={this.onSubmit}\n        />\n      </div>\n    )\n  }\n}\n"
  },
  {
    "path": "demo/src/components/Samples/Touch/index.txt",
    "content": "class Touch extends Component {\n  state = { allowTouch: true }\n\n  toggleAllowTouch = () => {\n    this.setState((prevState) => (\n      {allowTouch: !prevState.allowTouch}\n    ))\n  }\n\n  render () {\n    return (\n      <div>\n        <div>\n          <Button onClick={this.toggleAllowTouch}>\n            {this.state.allowTouch\n              ? \"Stop allowing touch\"\n              : \"Start allowing touch\"\n            }\n          </Button>\n        </div>\n        <Annotation\n          src={img}\n          alt='Two pebbles anthropomorphized holding hands'\n          annotations={this.state.annotations}\n          \n          allowTouch={this.state.allowTouch}\n\n          type={this.state.type}\n          value={this.state.annotation}\n          onChange={this.onChange}\n          onSubmit={this.onSubmit}\n        />\n      </div>\n    )\n  }\n}\n"
  },
  {
    "path": "demo/src/index.css",
    "content": "@import url('https://fonts.googleapis.com/css?family=Montserrat:700|Open+Sans');\n\nhtml, body {\n  margin: 0;\n}\n"
  },
  {
    "path": "demo/src/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n    <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge\">\n    <title><%= htmlWebpackPlugin.options.title %></title>\n    <!-- Start Single Page Apps for GitHub Pages -->\n    <script type=\"text/javascript\">\n      // Single Page Apps for GitHub Pages\n      // https://github.com/rafrex/spa-github-pages\n      // Copyright (c) 2016 Rafael Pedicini, licensed under the MIT License\n      // ----------------------------------------------------------------------\n      // This script checks to see if a redirect is present in the query string\n      // and converts it back into the correct url and adds it to the\n      // browser's history using window.history.replaceState(...),\n      // which won't cause the browser to attempt to load the new url.\n      // When the single page app is loaded further down in this file,\n      // the correct url will be waiting in the browser's history for\n      // the single page app to route accordingly.\n      (function(l) {\n        if (l.search) {\n          var q = {};\n          l.search.slice(1).split('&').forEach(function(v) {\n            var a = v.split('=');\n            q[a[0]] = a.slice(1).join('=').replace(/~and~/g, '&');\n          });\n          if (q.p !== undefined) {\n            window.history.replaceState(null, null,\n              l.pathname.slice(0, -1) + (q.p || '') +\n              (q.q ? ('?' + q.q) : '') +\n              l.hash\n            );\n          }\n        }\n      }(window.location))\n    </script>\n    <!-- End Single Page Apps for GitHub Pages -->\n    <script async defer src=\"https://buttons.github.io/buttons.js\"></script>\n  </head>\n  <body>\n    <div id=\"<%= htmlWebpackPlugin.options.mountId %>\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "demo/src/index.js",
    "content": "import React from 'react'\nimport ReactDOM from 'react-dom'\nimport './index.css'\nimport App from './App'\nimport registerServiceWorker from './registerServiceWorker'\n\nimport { registerLanguage } from 'react-syntax-highlighter/prism-light'\nimport jsx from 'react-syntax-highlighter/languages/prism/jsx'\n\nregisterLanguage('jsx', jsx)\n\nReactDOM.render(<App />, document.getElementById('demo'))\nregisterServiceWorker()\n"
  },
  {
    "path": "demo/src/mocks.js",
    "content": "import {\n  RectangleSelector,\n  OvalSelector\n} from '../../src/selectors'\n\nexport default {\n  annotations: [\n    {\n      geometry:\n      {\n        type: RectangleSelector.TYPE,\n        x: 25,\n        y: 31,\n        width: 21,\n        height: 35\n      },\n      data: {\n        text: 'Annotate!',\n        id: 1\n      }\n    },\n    {\n      geometry:\n      {\n        type: OvalSelector.TYPE,\n        x: 53,\n        y: 33,\n        width : 17.5,\n        height: 28\n      },\n      data: {\n        text: 'Supports custom shapes too!',\n        id: 2\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "demo/src/registerServiceWorker.js",
    "content": "// In production, we register a service worker to serve assets from local cache.\n\n// This lets the app load faster on subsequent visits in production, and gives\n// it offline capabilities. However, it also means that developers (and users)\n// will only see deployed updates on the \"N+1\" visit to a page, since previously\n// cached resources are updated in the background.\n\n// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.\n// This link also includes instructions on opting out of this behavior.\n\nconst isLocalhost = Boolean(\n  window.location.hostname === 'localhost' ||\n    // [::1] is the IPv6 localhost address.\n    window.location.hostname === '[::1]' ||\n    // 127.0.0.1/8 is considered localhost for IPv4.\n    window.location.hostname.match(\n      /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\n    )\n)\n\nexport default function register () {\n  if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\n    // The URL constructor is available in all browsers that support SW.\n    const publicUrl = new URL(process.env.PUBLIC_URL, window.location)\n    if (publicUrl.origin !== window.location.origin) {\n      // Our service worker won't work if PUBLIC_URL is on a different origin\n      // from what our page is served on. This might happen if a CDN is used to\n      // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374\n      return\n    }\n\n    window.addEventListener('load', () => {\n      const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`\n\n      if (isLocalhost) {\n        // This is running on localhost. Lets check if a service worker still exists or not.\n        checkValidServiceWorker(swUrl)\n      } else {\n        // Is not local host. Just register service worker\n        registerValidSW(swUrl)\n      }\n    })\n  }\n}\n\nfunction registerValidSW (swUrl) {\n  navigator.serviceWorker\n    .register(swUrl)\n    .then(registration => {\n      registration.onupdatefound = () => {\n        const installingWorker = registration.installing\n        installingWorker.onstatechange = () => {\n          if (installingWorker.state === 'installed') {\n            if (navigator.serviceWorker.controller) {\n              // At this point, the old content will have been purged and\n              // the fresh content will have been added to the cache.\n              // It's the perfect time to display a \"New content is\n              // available; please refresh.\" message in your web app.\n              console.log('New content is available; please refresh.')\n            } else {\n              // At this point, everything has been precached.\n              // It's the perfect time to display a\n              // \"Content is cached for offline use.\" message.\n              console.log('Content is cached for offline use.')\n            }\n          }\n        }\n      }\n    })\n    .catch(error => {\n      console.error('Error during service worker registration:', error)\n    })\n}\n\nfunction checkValidServiceWorker (swUrl) {\n  // Check if the service worker can be found. If it can't reload the page.\n  fetch(swUrl)\n    .then(response => {\n      // Ensure service worker exists, and that we really are getting a JS file.\n      if (\n        response.status === 404 ||\n        response.headers.get('content-type').indexOf('javascript') === -1\n      ) {\n        // No service worker found. Probably a different app. Reload the page.\n        navigator.serviceWorker.ready.then(registration => {\n          registration.unregister().then(() => {\n            window.location.reload()\n          })\n        })\n      } else {\n        // Service worker found. Proceed as normal.\n        registerValidSW(swUrl)\n      }\n    })\n    .catch(() => {\n      console.log(\n        'No internet connection found. App is running in offline mode.'\n      )\n    })\n}\n\nexport function unregister () {\n  if ('serviceWorker' in navigator) {\n    navigator.serviceWorker.ready.then(registration => {\n      registration.unregister()\n    })\n  }\n}\n"
  },
  {
    "path": "nwb.config.js",
    "content": "const path = require('path')\n\nmodule.exports = {\n  type: 'react-component',\n  npm: {\n    esModules: true,\n    umd: {\n      global: 'ReactImageAnnotation',\n      externals: {\n        react: 'React'\n      }\n    }\n  },\n  webpack: {\n    html: {\n      template: 'demo/src/index.html'\n    },\n    extra: {\n      module: {\n        rules: [\n          {test: /\\.txt/, loader: 'raw-loader'}\n        ]\n      }\n    }\n  },\n  karma: {\n    testContext: 'tests/index.test.js'\n  }\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"react-image-annotation\",\n  \"version\": \"0.9.10\",\n  \"description\": \"react-image-annotation React component\",\n  \"author\": \"Arian Allenson Valdez <arianallensonv@gmail.com> (http://arianv.com/)\",\n  \"main\": \"lib/index.js\",\n  \"module\": \"es/index.js\",\n  \"files\": [\n    \"css\",\n    \"es\",\n    \"lib\",\n    \"umd\"\n  ],\n  \"scripts\": {\n    \"build\": \"nwb build-react-component\",\n    \"deploy\": \"gh-pages -d demo/dist\",\n    \"clean\": \"nwb clean-module && nwb clean-demo\",\n    \"start\": \"nwb serve-react-demo\",\n    \"test\": \"nwb test-react\",\n    \"test:coverage\": \"nwb test-react --coverage\",\n    \"test:watch\": \"nwb test-react --server\"\n  },\n  \"dependencies\": {\n    \"styled-components\": \"^3.1.6\"\n  },\n  \"peerDependencies\": {\n    \"prop-types\": \"^15.6.0\",\n    \"react\": \"^16.3\",\n    \"react-dom\": \">=0.14\"\n  },\n  \"devDependencies\": {\n    \"chai\": \"^4.1.2\",\n    \"enzyme\": \"^3.3.0\",\n    \"enzyme-adapter-react-16\": \"^1.1.1\",\n    \"gh-pages\": \"^1.1.0\",\n    \"nwb\": \"0.21.x\",\n    \"raw-loader\": \"^0.5.1\",\n    \"react\": \"^16.8.6\",\n    \"react-dom\": \"^16.8.6\",\n    \"react-router\": \"^4.2.0\",\n    \"react-router-dom\": \"^4.2.2\",\n    \"react-syntax-highlighter\": \"^7.0.0\",\n    \"standard\": \"^10.0.3\"\n  },\n  \"standard\": {\n    \"env\": [\n      \"jest\",\n      \"jasmine\"\n    ],\n    \"globals\": [\n      \"fetch\",\n      \"URL\"\n    ],\n    \"parser\": \"babel-eslint\"\n  },\n  \"homepage\": \"\",\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/Secretmapper/react-image-annotation\"\n  },\n  \"keywords\": [\n    \"react-component\"\n  ]\n}\n"
  },
  {
    "path": "public/404.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <title>Single Page Apps for GitHub Pages</title>\n    <script type=\"text/javascript\">\n      // Single Page Apps for GitHub Pages\n      // https://github.com/rafrex/spa-github-pages\n      // Copyright (c) 2016 Rafael Pedicini, licensed under the MIT License\n      // ----------------------------------------------------------------------\n      // This script takes the current url and converts the path and query\n      // string into just a query string, and then redirects the browser\n      // to the new url with only a query string and hash fragment,\n      // e.g. http://www.foo.tld/one/two?a=b&c=d#qwe, becomes\n      // http://www.foo.tld/?p=/one/two&q=a=b~and~c=d#qwe\n      // Note: this 404.html file must be at least 512 bytes for it to work\n      // with Internet Explorer (it is currently > 512 bytes)\n      // If you're creating a Project Pages site and NOT using a custom domain,\n      // then set segmentCount to 1 (enterprise users may need to set it to > 1).\n      // This way the code will only replace the route part of the path, and not\n      // the real directory in which the app resides, for example:\n      // https://username.github.io/repo-name/one/two?a=b&c=d#qwe becomes\n      // https://username.github.io/repo-name/?p=/one/two&q=a=b~and~c=d#qwe\n      // Otherwise, leave segmentCount as 0.\n      var segmentCount = 1;\n      var l = window.location;\n      l.replace(\n        l.protocol + '//' + l.hostname + (l.port ? ':' + l.port : '') +\n        l.pathname.split('/').slice(0, 1 + segmentCount).join('/') + '/?p=/' +\n        l.pathname.slice(1).split('/').slice(segmentCount).join('/').replace(/&/g, '~and~') +\n        (l.search ? '&q=' + l.search.slice(1).replace(/&/g, '~and~') : '') +\n        l.hash\n      );\n    </script>\n  </head>\n  <body>\n  </body>\n</html>\n"
  },
  {
    "path": "src/components/Annotation.js",
    "content": "import React, { Component } from 'react'\nimport T from 'prop-types'\nimport styled from 'styled-components'\nimport compose from '../utils/compose'\nimport isMouseHovering from '../utils/isMouseHovering'\nimport withRelativeMousePos from '../utils/withRelativeMousePos'\n\nimport defaultProps from './defaultProps'\nimport Overlay from './Overlay'\n\nconst Container = styled.div`\n  clear: both;\n  position: relative;\n  width: 100%;\n  &:hover ${Overlay} {\n    opacity: 1;\n  }\n  touch-action: ${(props) => (props.allowTouch ? \"pinch-zoom\" : \"auto\")};\n`\n\nconst Img = styled.img`\n  display: block;\n  width: 100%;\n`\n\nconst Items = styled.div`\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  right: 0;\n`\n\nconst Target = Items\n\nexport default compose(\n  isMouseHovering(),\n  withRelativeMousePos()\n)(class Annotation extends Component {\n  static propTypes = {\n    innerRef: T.func,\n    onMouseUp: T.func,\n    onMouseDown: T.func,\n    onMouseMove: T.func,\n    onClick: T.func,\n    children: T.object,\n\n    annotations: T.arrayOf(\n      T.shape({\n        type: T.string\n      })\n    ).isRequired,\n    type: T.string,\n    selectors: T.arrayOf(\n      T.shape({\n        TYPE: T.string,\n        intersects: T.func.isRequired,\n        area: T.func.isRequired,\n        methods: T.object.isRequired\n      })\n    ).isRequired,\n\n    value: T.shape({\n      selection: T.object,\n      geometry: T.shape({\n        type: T.string.isRequired\n      }),\n      data: T.object\n    }),\n    onChange: T.func,\n    onSubmit: T.func,\n\n    activeAnnotationComparator: T.func,\n    activeAnnotations: T.arrayOf(T.any),\n\n    disableAnnotation: T.bool,\n    disableSelector: T.bool,\n    renderSelector: T.func,\n    disableEditor: T.bool,\n    renderEditor: T.func,\n\n    renderHighlight: T.func.isRequired,\n    renderContent: T.func.isRequired,\n\n    disableOverlay: T.bool,\n    renderOverlay: T.func.isRequired,\n    allowTouch: T.bool\n  }\n\n  static defaultProps = defaultProps\n\n  targetRef = React.createRef();\n  componentDidMount() {\n    if (this.props.allowTouch) {\n      this.addTargetTouchEventListeners();\n    }\n  }\n\n  addTargetTouchEventListeners = () => {\n    // Safari does not recognize touch-action CSS property,\n    // so we need to call preventDefault ourselves to stop touch from scrolling\n    // Event handlers must be set via ref to enable e.preventDefault()\n    // https://github.com/facebook/react/issues/9809\n    \n    this.targetRef.current.ontouchstart = this.onTouchStart;\n    this.targetRef.current.ontouchend = this.onTouchEnd;\n    this.targetRef.current.ontouchmove = this.onTargetTouchMove;\n    this.targetRef.current.ontouchcancel = this.onTargetTouchLeave;\n    \n  }\n  removeTargetTouchEventListeners = () => {\n    this.targetRef.current.ontouchstart = undefined;\n    this.targetRef.current.ontouchend = undefined;\n    this.targetRef.current.ontouchmove = undefined;\n    this.targetRef.current.ontouchcancel = undefined;\n  }\n\n  componentDidUpdate(prevProps) {\n    if (this.props.allowTouch !== prevProps.allowTouch) {\n      if (this.props.allowTouch) {\n        this.addTargetTouchEventListeners()\n      } else {\n        this.removeTargetTouchEventListeners()\n      }\n    }\n  }\n\n  setInnerRef = (el) => {\n    this.container = el\n    this.props.relativeMousePos.innerRef(el)\n    this.props.innerRef(el)\n  }\n\n  getSelectorByType = (type) => {\n    return this.props.selectors.find(s => s.TYPE === type)\n  }\n\n  getTopAnnotationAt = (x, y) => {\n    const { annotations } = this.props\n    const { container, getSelectorByType } = this\n\n    if (!container) return\n\n    const intersections = annotations\n      .map(annotation => {\n        const { geometry } = annotation\n        const selector = getSelectorByType(geometry.type)\n\n        return selector.intersects({ x, y }, geometry, container)\n          ? annotation\n          : false\n      })\n      .filter(a => !!a)\n      .sort((a, b) => {\n        const aSelector = getSelectorByType(a.geometry.type)\n        const bSelector = getSelectorByType(b.geometry.type)\n\n        return aSelector.area(a.geometry, container) - bSelector.area(b.geometry, container)\n      })\n\n    return intersections[0]\n  }\n\n  onTargetMouseMove = (e) => {\n    this.props.relativeMousePos.onMouseMove(e)\n    this.onMouseMove(e)\n  }\n  onTargetTouchMove = (e) => {\n    this.props.relativeMousePos.onTouchMove(e)\n    this.onTouchMove(e)\n  }\n\n  onTargetMouseLeave = (e) => {\n    this.props.relativeMousePos.onMouseLeave(e)\n  }\n  onTargetTouchLeave = (e) => {\n    this.props.relativeMousePos.onTouchLeave(e)\n  }\n\n  onMouseUp = (e) => this.callSelectorMethod('onMouseUp', e)\n  onMouseDown = (e) => this.callSelectorMethod('onMouseDown', e)\n  onMouseMove = (e) => this.callSelectorMethod('onMouseMove', e)\n  onTouchStart = (e) => this.callSelectorMethod(\"onTouchStart\", e)\n  onTouchEnd = (e) => this.callSelectorMethod(\"onTouchEnd\", e)\n  onTouchMove = (e) => this.callSelectorMethod(\"onTouchMove\", e)\n  onClick = (e) => this.callSelectorMethod('onClick', e)\n\n  onSubmit = () => {\n    this.props.onSubmit(this.props.value)\n  }\n\n  callSelectorMethod = (methodName, e) => {\n    if (this.props.disableAnnotation) {\n      return\n    }\n\n    if (!!this.props[methodName]) {\n      this.props[methodName](e)\n    } else {\n      const selector = this.getSelectorByType(this.props.type)\n      if (selector && selector.methods[methodName]) {\n        const value = selector.methods[methodName](this.props.value, e)\n\n        if (typeof value === 'undefined') {\n          if (process.env.NODE_ENV !== 'production') {\n            console.error(`\n              ${methodName} of selector type ${this.props.type} returned undefined.\n              Make sure to explicitly return the previous state\n            `)\n          }\n        } else {\n          this.props.onChange(value)\n        }\n      }\n    }\n  }\n\n  shouldAnnotationBeActive = (annotation, top) => {\n    if (this.props.activeAnnotations) {\n      const isActive = !!this.props.activeAnnotations.find(active => (\n        this.props.activeAnnotationComparator(annotation, active)\n      ))\n\n      return isActive || top === annotation\n    } else {\n      return top === annotation\n    }\n  }\n\n  \n\n  render () {\n    const { props } = this\n    const {\n      isMouseHovering,\n\n      renderHighlight,\n      renderContent,\n      renderSelector,\n      renderEditor,\n      renderOverlay,\n      allowTouch\n    } = props\n\n    const topAnnotationAtMouse = this.getTopAnnotationAt(\n      this.props.relativeMousePos.x,\n      this.props.relativeMousePos.y\n    )\n\n    return (\n      <Container\n        style={props.style}\n        innerRef={isMouseHovering.innerRef}\n        onMouseLeave={this.onTargetMouseLeave}\n        onTouchCancel={this.onTargetTouchLeave}\n        allowTouch={allowTouch}\n      >\n        <Img\n          className={props.className}\n          style={props.style}\n          alt={props.alt}\n          src={props.src}\n          draggable={false}\n          innerRef={this.setInnerRef}\n        />\n        <Items>\n          {props.annotations.map(annotation => (\n            renderHighlight({\n              key: annotation.data.id,\n              annotation,\n              active: this.shouldAnnotationBeActive(annotation, topAnnotationAtMouse)\n            })\n          ))}\n          {!props.disableSelector\n            && props.value\n            && props.value.geometry\n            && (\n              renderSelector({\n                annotation: props.value\n              })\n            )\n          }\n        </Items>\n        <Target\n          innerRef={this.targetRef}\n          onClick={this.onClick}\n          onMouseUp={this.onMouseUp}\n          onMouseDown={this.onMouseDown}\n          onMouseMove={this.onTargetMouseMove}\n        />\n        {!props.disableOverlay && (\n          renderOverlay({\n            type: props.type,\n            annotation: props.value\n          })\n        )}\n        {props.annotations.map(annotation => (\n          this.shouldAnnotationBeActive(annotation, topAnnotationAtMouse)\n          && (\n            renderContent({\n              key: annotation.data.id,\n              annotation: annotation\n            })\n          )\n        ))}\n        {!props.disableEditor\n          && props.value\n          && props.value.selection\n          && props.value.selection.showEditor\n          && (\n            renderEditor({\n              annotation: props.value,\n              onChange: props.onChange,\n              onSubmit: this.onSubmit\n            })\n          )\n        }\n        <div>{props.children}</div>\n      </Container>\n    )\n  }\n})\n"
  },
  {
    "path": "src/components/Content/index.js",
    "content": "import React from 'react'\nimport styled from 'styled-components'\n\nconst Container = styled.div`\n  background: white;\n  border-radius: 2px;\n  box-shadow:\n    0px 1px 5px 0px rgba(0, 0, 0, 0.2),\n    0px 2px 2px 0px rgba(0, 0, 0, 0.14),\n    0px 3px 1px -2px rgba(0, 0, 0, 0.12);\n  padding: 8px 16px;\n  margin-top: 8px;\n  margin-left: 8px;\n`\n\nfunction Content (props) {\n  const { geometry } = props.annotation\n  if (!geometry) return null\n\n  return (\n    <Container\n      style={{\n        position: 'absolute',\n        left: `${geometry.x}%`,\n        top: `${geometry.y + geometry.height}%`,\n        ...props.style\n      }}\n      className={props.className}\n      geometry={geometry}\n    >\n      {props.annotation.data && props.annotation.data.text}\n    </Container>\n  )\n}\n\nContent.defaultProps = {\n  style: {},\n  className: ''\n}\n\nexport default Content\n"
  },
  {
    "path": "src/components/Editor/index.js",
    "content": "import React from 'react'\nimport styled, { keyframes } from 'styled-components'\nimport TextEditor from '../TextEditor'\n\nconst fadeInScale = keyframes`\n  from {\n    opacity: 0;\n    transform: scale(0);\n  }\n\n  to {\n    opacity: 1;\n    transform: scale(1);\n  }\n`\n\nconst Container = styled.div`\n  background: white;\n  border-radius: 2px;\n  box-shadow:\n    0px 1px 5px 0px rgba(0, 0, 0, 0.2),\n    0px 2px 2px 0px rgba(0, 0, 0, 0.14),\n    0px 3px 1px -2px rgba(0, 0, 0, 0.12);\n  margin-top: 16px;\n  transform-origin: top left;\n\n  animation: ${fadeInScale} 0.31s cubic-bezier(0.175, 0.885, 0.32, 1.275);\n  overflow: hidden;\n`\n\nfunction Editor (props) {\n  const { geometry } = props.annotation\n  if (!geometry) return null\n\n  return (\n    <Container\n      className={props.className}\n      style={{\n        position: 'absolute',\n        left: `${geometry.x}%`,\n        top: `${geometry.y + geometry.height}%`,\n        ...props.style\n      }}\n    >\n      <TextEditor\n        onChange={e => props.onChange({\n          ...props.annotation,\n          data: {\n            ...props.annotation.data,\n            text: e.target.value\n          }\n        })}\n        onSubmit={props.onSubmit}\n        value={props.annotation.data && props.annotation.data.text}\n      />\n    </Container>\n  )\n}\n\nEditor.defaultProps = {\n  className: '',\n  style: {}\n}\n\nexport default Editor\n"
  },
  {
    "path": "src/components/FancyRectangle/index.js",
    "content": "import React from 'react'\nimport styled from 'styled-components'\n\nconst Box = styled.div`\n  background: rgba(0, 0, 0, 0.2);\n  position: absolute;\n`\n\nconst Container = styled.div`\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  right: 0;\n`\n\nfunction FancyRectangle (props) {\n  const { geometry } = props.annotation\n\n  if (!geometry) return null\n\n  return (\n    <Container\n      className={props.className}\n      style={props.style}\n    >\n      <Box\n        style={{\n          height: `${geometry.y}%`,\n          width: '100%'\n        }}\n      />\n      <Box\n        style={{\n          top: `${geometry.y}%`,\n          height: `${geometry.height}%`,\n          width: `${geometry.x}%`\n        }}\n      />\n      <Box\n        style={{\n          top: `${geometry.y}%`,\n          left: `${geometry.x + geometry.width}%`,\n          height: `${geometry.height}%`,\n          width: `${100 - (geometry.x + geometry.width)}%`\n        }}\n      />\n      <Box\n        style={{\n          top: `${geometry.y + geometry.height}%`,\n          height: `${100 - (geometry.y + geometry.height)}%`,\n          width: '100%'\n        }}\n      />\n    </Container>\n  )\n}\n\nFancyRectangle.defaultProps = {\n  className: '',\n  style: {}\n}\n\nexport default FancyRectangle\n"
  },
  {
    "path": "src/components/Oval/index.js",
    "content": "import React from 'react'\nimport styled from 'styled-components'\n\nconst Container = styled.div`\n  border: dashed 2px black;\n  border-radius: 100%;\n  box-shadow: 0px 0px 1px 1px white inset;\n  box-sizing: border-box;\n  transition: box-shadow 0.21s ease-in-out;\n`\n\nfunction Oval (props) {\n  const { geometry } = props.annotation\n  if (!geometry) return null\n\n  return (\n    <Container\n      className={props.className}\n      style={{\n        position: 'absolute',\n        left: `${geometry.x}%`,\n        top: `${geometry.y}%`,\n        height: `${geometry.height}%`,\n        width: `${geometry.width}%`,\n        boxShadow: props.active && '0 0 1px 1px yellow inset',\n        ...props.style\n      }}\n    />\n  )\n}\n\nOval.defaultProps = {\n  className: '',\n  style: {}\n}\n\nexport default Oval\n"
  },
  {
    "path": "src/components/Overlay/index.js",
    "content": "import React from 'react'\nimport styled from 'styled-components'\n\nexport default styled.div`\n  background: rgba(0, 0, 0, .4);\n  border-radius: 5px;\n  bottom: 4px;\n  color: white;\n  font-size: 12px;\n  font-weight: bold;\n  opacity: 0;\n  padding: 10px;\n  pointer-events: none;\n  position: absolute;\n  right: 4px;\n  transition: opacity 0.21s ease-in-out;\n  user-select: none;\n`\n"
  },
  {
    "path": "src/components/Point/index.js",
    "content": "import React from 'react'\nimport styled from 'styled-components'\n\nconst Container = styled.div`\n  border: solid 3px white;\n  border-radius: 50%;\n  box-sizing: border-box;\n  box-shadow:\n    0 0 0 1px rgba(0,0,0,0.3),\n    0 0 0 2px rgba(0,0,0,0.2),\n    0 5px 4px rgba(0,0,0,0.4);\n  height: 16px;\n  position: absolute;\n  transform: translate3d(-50%, -50%, 0);\n  width: 16px;\n` \n\nfunction Point (props) {\n  const { geometry } = props.annotation\n  if (!geometry) return null\n\n  return (\n    <Container\n      style={{\n        top: `${geometry.y}%`,\n        left: `${geometry.x}%`\n      }}\n    />\n  )\n}\n\n\nexport default Point\n"
  },
  {
    "path": "src/components/Rectangle/index.js",
    "content": "import React from 'react'\nimport styled from 'styled-components'\n\nconst Container = styled.div`\n  border: dashed 2px black;\n  box-shadow: 0px 0px 1px 1px white inset;\n  box-sizing: border-box;\n  transition: box-shadow 0.21s ease-in-out;\n`\n\nfunction Rectangle (props) {\n  const { geometry } = props.annotation\n  if (!geometry) return null\n\n  return (\n    <Container\n      className={props.className}\n      style={{\n        position: 'absolute',\n        left: `${geometry.x}%`,\n        top: `${geometry.y}%`,\n        height: `${geometry.height}%`,\n        width: `${geometry.width}%`,\n        boxShadow: props.active && '0 0 1px 1px yellow inset',\n        ...props.style\n      }}\n    />\n  )\n}\n\nRectangle.defaultProps = {\n  className: '',\n  style: {}\n}\n\nexport default Rectangle\n"
  },
  {
    "path": "src/components/TextEditor/index.js",
    "content": "import React from 'react'\nimport styled, { keyframes } from 'styled-components'\n\nconst Inner = styled.div`\n  padding: 8px 16px;\n\n  textarea {\n    border: 0;\n    font-size: 14px;\n    margin: 6px 0;\n    min-height: 60px;\n    outline: 0;\n  }\n`\n\nconst Button = styled.div`\n  background: whitesmoke;\n  border: 0;\n  box-sizing: border-box;\n  color: #363636;\n  cursor: pointer;\n  font-size: 1rem;\n  margin: 0;\n  outline: 0;\n  padding: 8px 16px;\n  text-align: center;\n  text-shadow: 0 1px 0 rgba(0,0,0,0.1);\n  width: 100%;\n\n  transition: background 0.21s ease-in-out;\n\n  &:focus, &:hover {\n    background: #eeeeee;\n  }\n`\n\nfunction TextEditor (props) {\n  return (\n    <React.Fragment>\n      <Inner>\n        <textarea\n          placeholder='Write description'\n          onFocus={props.onFocus}\n          onBlur={props.onBlur}\n          onChange={props.onChange}\n          value={props.value}\n        >\n        </textarea>\n      </Inner>\n      {props.value && (\n        <Button\n          onClick={props.onSubmit}\n        >\n          Submit\n        </Button>\n      )}\n    </React.Fragment>\n  )\n}\n\nexport default TextEditor\n"
  },
  {
    "path": "src/components/defaultProps.js",
    "content": "import React from 'react'\n\nimport Point from './Point'\nimport Editor from './Editor'\nimport FancyRectangle from './FancyRectangle'\nimport Rectangle from './Rectangle'\nimport Oval from './Oval'\nimport Content from './Content'\nimport Overlay from './Overlay'\n\nimport {\n  RectangleSelector,\n  PointSelector,\n  OvalSelector\n} from '../selectors'\n\nexport default {\n  innerRef: () => {},\n  onChange: () => {},\n  onSubmit: () => {},\n  type: RectangleSelector.TYPE,\n  selectors: [\n    RectangleSelector,\n    PointSelector,\n    OvalSelector\n  ],\n  disableAnnotation: false,\n  disableSelector: false,\n  disableEditor: false,\n  disableOverlay: false,\n  activeAnnotationComparator: (a, b) => a === b,\n  renderSelector: ({ annotation }) => {\n    switch (annotation.geometry.type) {\n      case RectangleSelector.TYPE:\n        return (\n          <FancyRectangle\n            annotation={annotation}\n          />\n        )\n      case PointSelector.TYPE:\n        return (\n          <Point\n            annotation={annotation}\n          />\n        )\n      case OvalSelector.TYPE:\n        return (\n          <Oval\n            annotation={annotation}\n          />\n        )\n      default:\n        return null\n    }\n  },\n  renderEditor: ({ annotation, onChange, onSubmit }) => (\n    <Editor\n      annotation={annotation}\n      onChange={onChange}\n      onSubmit={onSubmit}\n    />\n  ),\n  renderHighlight: ({ key, annotation, active }) => {\n    switch (annotation.geometry.type) {\n      case RectangleSelector.TYPE:\n        return (\n          <Rectangle\n            key={key}\n            annotation={annotation}\n            active={active}\n          />\n        )\n      case PointSelector.TYPE:\n        return (\n          <Point\n            key={key}\n            annotation={annotation}\n            active={active}\n          />\n        )\n      case OvalSelector.TYPE:\n        return (\n          <Oval\n            key={key}\n            annotation={annotation}\n            active={active}\n          />\n        )\n      default:\n        return null\n    }\n  },\n  renderContent: ({ key, annotation }) => (\n    <Content\n      key={key}\n      annotation={annotation}\n    />\n  ),\n  renderOverlay: ({ type, annotation }) => {\n    switch (type) {\n      case PointSelector.TYPE:\n        return (\n          <Overlay>\n            Click to Annotate\n          </Overlay>\n        )\n      default:\n        return (\n          <Overlay>\n            Click and Drag to Annotate\n          </Overlay>\n        )\n    }\n  }\n}\n"
  },
  {
    "path": "src/hocs/OvalSelector.js",
    "content": "import { getCoordPercentage } from '../utils/offsetCoordinates';\n\nconst square = n => Math.pow(n, 2)\n\nexport const TYPE = 'OVAL'\n\nexport function intersects({ x, y }, geometry) {\n  const rx = geometry.width / 2\n  const ry = geometry.height / 2\n  const h = geometry.x + rx\n  const k = geometry.y + ry\n\n  const value = square(x - h) / square(rx) + square(y - k) / square(ry)\n\n  return value <= 1\n}\n\nexport function area(geometry) {\n  const rx = geometry.width / 2\n  const ry = geometry.height / 2\n\n  return Math.PI * rx * ry\n}\n\nexport const methods = {\n  onTouchStart(annotation, e) {\n    return pointerDown(annotation, e)\n  },\n  onTouchEnd(annotation, e) {\n    return pointerUp(annotation, e)\n  },\n  onTouchMove(annotation, e) {\n    return pointerMove(annotation, e)\n  },\n  onMouseDown(annotation, e) {\n    return pointerDown(annotation, e)\n  },\n  onMouseUp(annotation, e) {\n    return pointerUp(annotation, e)\n  },\n  onMouseMove(annotation, e) {\n    return pointerMove(annotation, e)\n  }\n}\n\nfunction pointerDown(annotation, e) {\n  if (!annotation.selection) {\n    const { x: anchorX, y: anchorY } = getCoordPercentage(e)\n\n    return {\n      ...annotation,\n      selection: {\n        ...annotation.selection,\n        mode: 'SELECTING',\n        anchorX,\n        anchorY\n      }\n    }\n  } else {\n    return {}\n  }\n  return annotation\n}\n\nfunction pointerUp(annotation, e) {\n  if (annotation.selection) {\n    const { selection, geometry } = annotation\n\n    if (!geometry) {\n      return {}\n    }\n\n    switch (annotation.selection.mode) {\n      case 'SELECTING':\n        return {\n          ...annotation,\n          selection: {\n            ...annotation.selection,\n            showEditor: true,\n            mode: 'EDITING'\n          }\n        }\n      default:\n        break\n    }\n  }\n  return annotation\n}\n\nfunction pointerMove(annotation, e) {\n  if (annotation.selection && annotation.selection.mode === 'SELECTING') {\n    const { anchorX, anchorY } = annotation.selection\n    const { x: newX, y: newY } = getCoordPercentage(e)\n    const width = newX - anchorX\n    const height = newY - anchorY\n\n    return {\n      ...annotation,\n      geometry: {\n        ...annotation.geometry,\n        type: TYPE,\n        x: width > 0 ? anchorX : newX,\n        y: height > 0 ? anchorY : newY,\n        width: Math.abs(width),\n        height: Math.abs(height)\n      }\n    }\n  }\n  return annotation\n}\n\nexport default {\n  TYPE,\n  intersects,\n  area,\n  methods\n}\n"
  },
  {
    "path": "src/hocs/PointSelector.js",
    "content": "import { getCoordPercentage } from '../utils/offsetCoordinates';\nconst MARGIN = 6\n\nconst marginToPercentage = (container) => ({\n  marginX: MARGIN / container.width * 100,\n  marginY: MARGIN / container.height * 100\n})\n\nexport const TYPE = 'POINT'\n\nexport function intersects ({ x, y }, geometry, container) {\n  const { marginX, marginY } = marginToPercentage(container)\n\n  if (x < geometry.x - marginX) return false\n  if (y < geometry.y - marginY) return false\n  if (x > geometry.x + marginX) return false\n  if (y > geometry.y + marginY) return false\n\n  return true\n}\n\nexport function area (geometry, container) {\n  const { marginX, marginY } = marginToPercentage(container)\n\n  return marginX * marginY\n}\n\nexport const methods = {\n  onClick (annotation, e) {\n    if (!annotation.geometry) {\n      return {\n        ...annotation,\n        selection: {\n          ...annotation.selection,\n          showEditor: true,\n          mode: 'EDITING'\n        },\n        geometry: {\n          ...annotation.geometry,\n          ...getCoordPercentage(e),\n          width: 0,\n          height: 0,\n          type: TYPE,\n        }\n      }\n    } else{\n      return {}\n    }\n  }\n}\n\nexport default {\n  TYPE,\n  intersects,\n  area,\n  methods\n}\n"
  },
  {
    "path": "src/hocs/RectangleSelector.js",
    "content": "import { getCoordPercentage } from '../utils/offsetCoordinates';\n\nexport const TYPE = 'RECTANGLE'\n\nexport function intersects({ x, y }, geometry) {\n  if (x < geometry.x) return false\n  if (y < geometry.y) return false\n  if (x > geometry.x + geometry.width) return false\n  if (y > geometry.y + geometry.height) return false\n\n  return true\n}\n\nexport function area(geometry) {\n  return geometry.height * geometry.width\n}\n\nexport const methods = {\n  onTouchStart(annotation, e) {\n    return pointerDown(annotation, e)\n  },\n  onTouchEnd(annotation, e) {\n    return pointerUp(annotation, e)\n  },\n  onTouchMove(annotation, e) {\n    return pointerMove(annotation, e)\n  },\n  onMouseDown(annotation, e) {\n    return pointerDown(annotation, e)\n  },\n  onMouseUp(annotation, e) {\n    return pointerUp(annotation, e)\n  },\n  onMouseMove(annotation, e) {\n    return pointerMove(annotation, e)\n  }\n}\n\nfunction pointerDown(annotation, e) {\n  if (!annotation.selection) {\n    const { x: anchorX, y: anchorY } = getCoordPercentage(e)\n    return {\n      ...annotation,\n      selection: {\n        ...annotation.selection,\n        mode: 'SELECTING',\n        anchorX,\n        anchorY\n      }\n    }\n  } else {\n    return {}\n  }\n}\n\nfunction pointerUp(annotation, e) {\n  if (annotation.selection) {\n    const { selection, geometry } = annotation\n    if (!geometry) {\n      return {}\n    }\n    switch (annotation.selection.mode) {\n      case 'SELECTING':\n        return {\n          ...annotation,\n          selection: {\n            ...annotation.selection,\n            showEditor: true,\n            mode: 'EDITING'\n          }\n        }\n      default:\n        break\n    }\n  }\n  return annotation\n}\n\nfunction pointerMove(annotation, e) {\n  if (annotation.selection && annotation.selection.mode === 'SELECTING') {\n    const { anchorX, anchorY } = annotation.selection\n    const { x: newX, y: newY } = getCoordPercentage(e)\n    const width = newX - anchorX\n    const height = newY - anchorY\n\n    return {\n      ...annotation,\n      geometry: {\n        ...annotation.geometry,\n        type: TYPE,\n        x: width > 0 ? anchorX : newX,\n        y: height > 0 ? anchorY : newY,\n        width: Math.abs(width),\n        height: Math.abs(height)\n      }\n    }\n  }\n  return annotation\n}\n\nexport default {\n  TYPE,\n  intersects,\n  area,\n  methods\n}\n"
  },
  {
    "path": "src/index.js",
    "content": "import Annotation from './components/Annotation'\nexport { default as defaultProps } from './components/defaultProps'\n\nexport default Annotation\n"
  },
  {
    "path": "src/selectors.js",
    "content": "export { default as RectangleSelector } from './hocs/RectangleSelector'\nexport { default as PointSelector } from './hocs/PointSelector'\nexport { default as OvalSelector } from './hocs/OvalSelector'\n"
  },
  {
    "path": "src/types/index.d.ts",
    "content": "declare module \"react-image-annotation\" {\n  export interface IGeometry {\n    type: string;\n    x?: number;\n    y?: number;\n    height?: number;\n    width?: number;\n  }\n  export interface ISelector {\n    TYPE: string;\n    intersects: (\n      { x, y }: { x: number; y: number },\n      geometry: IGeometry,\n      container: { width: number; height: number }\n    ) => boolean;\n    area: (\n      geometry: IGeometry,\n      container: { width: number; height: number }\n    ) => number;\n    methods: {\n      onMouseUp?: (annotation: IAnnotation, e: any) => IAnnotation | {};\n      onMouseDown?: (annotation: IAnnotation, e: any) => IAnnotation | {};\n      onMouseMove?: (annotation: IAnnotation, e: any) => IAnnotation | {};\n      onClick?: (annotation: IAnnotation, e: any) => IAnnotation | {};\n    };\n  }\n  export interface IAnnotation {\n    selection?: {\n      mode: string;\n      showEditor: boolean;\n    };\n    geometry: IGeometry;\n    data: {\n      text: string;\n      id?: number;\n    };\n  }\n  interface IAnnotationProps {\n    src: string;\n    alt?: string;\n    innerRef?: (e: any) => any;\n    onMouseUp?: (e: React.MouseEvent) => any;\n    onMouseDown?: (e: React.MouseEvent) => any;\n    onMouseMove?: (e: React.MouseEvent) => any;\n    onClick?: (e: React.MouseEvent) => any;\n\n    annotations: IAnnotation[];\n    type?: string;\n    selectors?: ISelector[];\n\n    value: IAnnotation | {};\n    onChange?: (e: any) => any;\n    onSubmit?: (e: any) => any;\n\n    activeAnnotationComparator?: (annotation: IAnnotation) => boolean;\n    activeAnnotations?: IAnnotation[];\n\n    disableAnnotation?: boolean;\n    disableSelector?: boolean;\n    renderSelector?: (\n      { annotation, active }: { annotation: IAnnotation; active: boolean }\n    ) => any;\n    disableEditor?: boolean;\n    renderEditor?: (\n      {\n        annotation,\n        onChange,\n        onSubmit\n      }: {\n        annotation: IAnnotation;\n        onChange: (annotation: IAnnotation | {}) => any;\n        onSubmit: (e?: any) => any;\n      }\n    ) => any;\n\n    renderHighlight?: (\n      { annotation, active }: { annotation: IAnnotation; active: boolean }\n    ) => any;\n    renderContent?: ({ annotation }: { annotation: IAnnotation }) => any;\n\n    disableOverlay?: boolean;\n    renderOverlay?: () => any;\n    allowTouch: boolean;\n  }\n\n  class Annotation extends React.Component<IAnnotationProps, {}> {}\n  export default Annotation;\n}\n"
  },
  {
    "path": "src/utils/compose.js",
    "content": "export default function compose (...funcs) {\n  if (funcs.length === 0) {\n    return arg => arg\n  }\n\n  if (funcs.length === 1) {\n    return funcs[0]\n  }\n\n  return funcs.reduce((a, b) => (...args) => a(b(...args)))\n}\n"
  },
  {
    "path": "src/utils/isMouseHovering.js",
    "content": "import React, { PureComponent as Component } from 'react'\n\nconst isMouseOverElement = ({ elem, e }) => {\n  const { pageY, pageX } = e\n  const { left, right, bottom, top } = elem.getBoundingClientRect()\n\n  return pageX > left && pageX < right && pageY > top && pageY < bottom\n}\n\nconst isMouseHovering = (key = 'isMouseHovering') => DecoratedComponent => {\n  class IsMouseHovering extends Component {\n    constructor() {\n      super()\n\n      this.state = {\n        isHoveringOver: false\n      }\n    }\n\n    componentDidMount() {\n      document.addEventListener('mousemove', this.onMouseMove)\n    }\n\n    componentWillUnmount() {\n      document.removeEventListener('mousemove', this.onMouseMove)\n    }\n\n    onMouseMove = e => {\n      const elem = this.el\n\n      this.setState({\n        isHoveringOver: isMouseOverElement({ elem, e })\n      })\n    }\n\n    render() {\n      const hocProps = {\n        [key]: {\n          innerRef: el => this.el = el,\n          isHoveringOver: this.state.isHoveringOver\n        }\n      }\n\n      return (\n        <DecoratedComponent\n          {...this.props}\n          {...hocProps}\n        />\n      )\n    }\n  }\n\n  IsMouseHovering.displayName = `IsMouseHovering(${DecoratedComponent.displayName})`\n\n  return IsMouseHovering\n}\n\nexport default isMouseHovering\n"
  },
  {
    "path": "src/utils/offsetCoordinates.js",
    "content": "const getMouseRelativeCoordinates = e => {\n    // nativeEvent.offsetX gives inconsistent results when dragging\n    // up and to the left rather than the more natural down and to the\n    // right. The reason could be browser implementation (it is still experimental)\n    // or it could be that nativeEvent offsets are based on target rather than\n    // currentTarget.\n    // To keep consistent behavior of the selector use the bounding client rect.\n    const rect = e.currentTarget.getBoundingClientRect();\n    const offsetX = e.clientX - rect.x;\n    const offsetY = e.clientY - rect.y;\n\n    return {\n        x: offsetX / rect.width * 100,\n        y: offsetY / rect.height * 100\n    };\n}\n\nconst clamp = (a, b, i) => Math.max(a, Math.min(b, i))\nconst getTouchRelativeCoordinates = e => {\n  const touch = e.targetTouches[0]\n\n  const boundingRect = e.currentTarget.getBoundingClientRect()\n  // https://idiallo.com/javascript/element-postion\n  // https://stackoverflow.com/questions/25630035/javascript-getboundingclientrect-changes-while-scrolling\n  const offsetX = touch.pageX - boundingRect.left\n  const offsetY = touch.pageY - (boundingRect.top + window.scrollY)\n\n  return {\n    x: clamp(0, 100, (offsetX / boundingRect.width) * 100),\n    y: clamp(0, 100, (offsetY / boundingRect.height) * 100)\n  }\n}\n\nconst getCoordPercentage = (e) => {\n  if (isTouchEvent(e)) {\n    if (isValidTouchEvent(e)) {\n      isTouchMoveEvent(e) && e.preventDefault()\n      return getTouchRelativeCoordinates(e)\n    } else {\n      return {\n        x: null\n      }\n    }\n  } else {\n    return getMouseRelativeCoordinates(e)\n  }\n}\n\nconst isTouchEvent = e => e.targetTouches !== undefined\nconst isValidTouchEvent = e => e.targetTouches.length === 1\nconst isTouchMoveEvent = e => e.type === 'touchmove'\n\nexport { getMouseRelativeCoordinates as getOffsetCoordPercentage, getCoordPercentage };\n"
  },
  {
    "path": "src/utils/withRelativeMousePos.js",
    "content": "import React, { PureComponent as Component } from 'react'\nimport { getOffsetCoordPercentage } from './offsetCoordinates';\n\nconst withRelativeMousePos = (key = 'relativeMousePos') => DecoratedComponent => {\n  class WithRelativeMousePos extends Component {\n    state = { x: null, y: null }\n\n    innerRef = el => {\n      this.container = el\n    }\n\n    onMouseMove = (e) => {\n      const xystate = getOffsetCoordPercentage(e, this.container);\n      this.setState(xystate);\n    }\n    onTouchMove = (e) => {\n      if (e.targetTouches.length === 1) {\n        const touch = e.targetTouches[0]\n\n        const offsetX = touch.pageX - this.container.offsetParent.offsetLeft\n        const offsetY = touch.pageY - this.container.offsetParent.offsetTop\n\n        this.setState({\n          x: (offsetX / this.container.width) * 100,\n          y: (offsetY / this.container.height) * 100\n        })\n      }\n    }\n\n    onMouseLeave = (e) => {\n      this.setState({ x: null, y: null })\n    }\n    onTouchLeave = (e) => {\n      this.setState({ x: null, y: null })\n    }\n\n    render () {\n      const hocProps = {\n        [key]: {\n          innerRef: this.innerRef,\n          onMouseMove: this.onMouseMove,\n          onMouseLeave: this.onMouseLeave,\n          onTouchMove: this.onTouchMove,\n          onTouchLeave: this.onTouchLeave,\n          x: this.state.x,\n          y: this.state.y\n        }\n      }\n\n      return (\n        <DecoratedComponent\n          {...this.props}\n          {...hocProps}\n        />\n      )\n    }\n  }\n\n  WithRelativeMousePos.displayName = `withRelativeMousePos(${DecoratedComponent.displayName})`\n\n  return WithRelativeMousePos\n}\n\nexport default withRelativeMousePos\n"
  },
  {
    "path": "tests/.eslintrc",
    "content": "{\n  \"env\": {\n    \"mocha\": true\n  }\n}\n"
  },
  {
    "path": "tests/Annotation.spec.js",
    "content": "import { mount } from 'enzyme'\nimport { expect } from 'chai'\nimport React from 'react'\n\nimport Annotation from '../src/components/Annotation'\n\nconst requiredProps = {\n  annotations: []\n}\n\ndescribe('Annotation', () => {\n  describe('render', () => {\n    it('renders <Annotation />', () => {\n      const wrapper = mount(<Annotation {...requiredProps} />)\n      expect(wrapper.find('Annotation')).to.have.length(1)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/index.test.js",
    "content": "import Enzyme from 'enzyme'\nimport Adapter from 'enzyme-adapter-react-16'\n\nEnzyme.configure({ adapter: new Adapter() })\n\nlet context = require.context('./', true, /\\.spec\\.js$/)\ncontext.keys().forEach(context)\n"
  },
  {
    "path": "tests/selectors/OvalSelector.spec.js",
    "content": "import { mount } from 'enzyme'\nimport { expect } from 'chai'\nimport React from 'react'\n\nimport { OvalSelector as selector } from '../../src/selectors'\n\nfunction createOval ({ x, y, width, height } = { x: 10, y: 10, width: 20, height: 10 }) {\n  return {\n    x, y, width, height\n  }\n}\n\ndescribe('OvalSelector', () => {\n  describe('TYPE', () => {\n    it('should be a defined string', () => {\n      expect(selector.TYPE).to.be.a('string')\n    })\n  })\n\n  describe('intersects', () => {\n    it('should return true when point is inside geometry', () => {\n      expect(\n        selector.intersects({ x: 15, y: 15 }, createOval())\n      ).to.be.true\n\n      const x = 15\n      const y = 17\n      expect(\n        selector.intersects({ x, y }, createOval())\n      ).to.be.true\n    })\n    it('should return false when point is outside of geometry', () => {\n      expect(selector.intersects({ x: 0, y: 0 }, createOval())).to.be.false\n      expect(selector.intersects({ x: 10, y: 0 }, createOval())).to.be.false\n      expect(selector.intersects({ x: 0, y: 10 }, createOval())).to.be.false\n      expect(selector.intersects({ x: 30, y: 30 }, createOval())).to.be.false\n    })\n  })\n\n  describe('area', () => {\n    it('should return geometry area', () => {\n      expect(selector.area(createOval())).to.equal(157.07963267948966)\n    })\n  })\n\n  describe('methods', () => {\n    xit('should be defined')\n  })\n})\n"
  },
  {
    "path": "tests/selectors/PointSelector.spec.js",
    "content": "import { mount } from 'enzyme'\nimport { expect } from 'chai'\nimport React from 'react'\n\nimport { PointSelector as selector } from '../../src/selectors'\n\nfunction createPoint ({ x, y } = { x: 10, y: 10 }) {\n  return { x, y }\n}\n\nfunction createContainer({ width, height } = { width: 100, height: 100 }) {\n  return { width, height }\n}\n\ndescribe('PoinntSelector', () => {\n  describe('TYPE', () => {\n    it('should be a defined string', () => {\n      expect(selector.TYPE).to.be.a('string')\n    })\n  })\n\n  describe('intersects', () => {\n    it('should return true when point is inside geometry', () => {\n      expect(\n        selector.intersects({ x: 10, y: 10 }, createPoint(), createContainer())\n      ).to.be.true\n    })\n    it('should return false when point is outside of geometry', () => {\n      expect(selector.intersects({ x: 0, y: 0 }, createPoint(), createContainer())).to.be.false\n      expect(selector.intersects({ x: 10, y: 0 }, createPoint(), createContainer())).to.be.false\n      expect(selector.intersects({ x: 0, y: 10 }, createPoint(), createContainer())).to.be.false\n      expect(selector.intersects({ x: 30, y: 30 }, createPoint(), createContainer())).to.be.false\n    })\n  })\n\n  describe('area', () => {\n    it('should return geometry area', () => {\n      expect(\n        selector.area(createPoint(), createContainer())\n      ).to.equal(36)\n    })\n    it('should return geometry area based on container', () => {\n      expect(\n        selector.area(createPoint(), createContainer({ width: 200, height: 200 }))\n      ).to.equal(9)\n    })\n  })\n\n  describe('methods', () => {\n    xit('should be defined')\n  })\n})\n"
  },
  {
    "path": "tests/selectors/RectangleSelector.spec.js",
    "content": "import { mount } from 'enzyme'\nimport { expect } from 'chai'\nimport React from 'react'\n\nimport { RectangleSelector as selector } from '../../src/selectors'\n\nfunction createRect ({ x, y, width, height } = { x: 10, y: 10, width: 10, height: 10 }) {\n  return {\n    x, y, width, height\n  }\n}\n\ndescribe('RectangleSelector', () => {\n  describe('TYPE', () => {\n    it('should be a defined string', () => {\n      expect(selector.TYPE).to.be.a('string')\n    })\n  })\n\n  describe('intersects', () => {\n    it('should return true when point is on top left of geometry', () => {\n      expect(\n        selector.intersects({ x: 10, y: 10 }, createRect())\n      ).to.be.true\n    })\n    it('should return true when point is on top right of geometry', () => {\n      expect(\n        selector.intersects({ x: 20, y: 10 }, createRect())\n      ).to.be.true\n    })\n    it('should return true when point is on bottom left of geometry', () => {\n      expect(\n        selector.intersects({ x: 10, y: 20 }, createRect())\n      ).to.be.true\n    })\n    it('should return true when point is on bottom right of geometry', () => {\n      expect(\n        selector.intersects({ x: 20, y: 20 }, createRect())\n      ).to.be.true\n    })\n    it('should return true when point is inside geometry', () => {\n      expect(\n        selector.intersects({ x: 15, y: 15 }, createRect())\n      ).to.be.true\n    })\n    it('should return false when point is outside of geometry', () => {\n      expect(selector.intersects({ x: 0, y: 0 }, createRect())).to.be.false\n      expect(selector.intersects({ x: 10, y: 0 }, createRect())).to.be.false\n      expect(selector.intersects({ x: 0, y: 10 }, createRect())).to.be.false\n      expect(selector.intersects({ x: 30, y: 30 }, createRect())).to.be.false\n    })\n  })\n\n  describe('area', () => {\n    it('should return geometry area', () => {\n      expect(selector.area(createRect({ width: 10, height: 10 }))).to.equal(100)\n    })\n  })\n\n  describe('methods', () => {\n    xit('should be defined')\n  })\n})\n"
  }
]