[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [\n    \"@babel/preset-react\"\n  ],\n  \"env\": {\n    \"test\": {\n      \"presets\": [\n        \"@babel/env\",\n        \"@babel/preset-typescript\"\n      ],\n      \"plugins\": [\n        \"@babel/transform-runtime\",\n        \"@babel/plugin-proposal-class-properties\"\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": ".codesandbox/ci.json",
    "content": "{\n  \"sandboxes\": [\n    \"github/handsontable/examples/tree/master/react/pull-request\"\n  ]\n}\n"
  },
  {
    "path": ".config/base.js",
    "content": "import nodeResolve from 'rollup-plugin-node-resolve';\nimport babel from 'rollup-plugin-babel';\nimport typescript from 'rollup-plugin-typescript2';\nimport json from 'rollup-plugin-json';\nimport commonjs from 'rollup-plugin-commonjs';\n\nexport const plugins = {\n  typescript: typescript(),\n  babel: babel({\n    babelrc: false,\n    exclude: ['/node_modules/', '**.json'],\n    extensions: ['.js', '.ts', '.tsx', '.jsx'],\n    presets: [\n      '@babel/env'\n    ],\n  }),\n  nodeResolve: nodeResolve(),\n  json: json({\n    include: 'package.json',\n    compact: true\n  }),\n  commonjs: commonjs({\n    include: [\n      'node_modules/**',\n      'src/lib/**'\n    ]\n  })\n};\n\nexport const baseConfig = {\n  input: 'src/index.tsx',\n  plugins: [\n    plugins.json,\n    plugins.replace,\n    plugins.commonjs,\n    plugins.typescript,\n    plugins.babel,\n    plugins.nodeResolve,\n  ],\n  external: [\n    'react',\n    'react-dom',\n    'handsontable'\n  ],\n};\n"
  },
  {
    "path": ".config/commonjs.js",
    "content": "import typescript from 'rollup-plugin-typescript2';\nimport { baseConfig, plugins } from './base';\n\nconst env = process.env.NODE_ENV;\nconst filename = 'react-handsontable.js';\n\nexport const cjsConfig = {\n  output: {\n    format: env,\n    indent: false,\n    file: `./commonjs/${filename}`,\n    exports: 'named'\n  },\n  plugins: baseConfig.plugins,\n};\n"
  },
  {
    "path": ".config/es.js",
    "content": "import typescript from 'rollup-plugin-typescript2';\nimport { baseConfig } from './base';\nimport { plugins } from './base';\n\nconst env = process.env.NODE_ENV;\nconst filename = 'react-handsontable.js';\n\nexport const esConfig = {\n  output: {\n    format: env,\n    indent: false,\n    file: `./es/${filename}`\n  },\n  plugins: [\n    plugins.json,\n    plugins.replace,\n    plugins.commonjs,\n    typescript({\n      tsconfigOverride: {\n        compilerOptions: {\n          declaration: true\n        }\n      },\n      useTsconfigDeclarationDir: true,\n    }),\n    plugins.babel,\n    plugins.nodeResolve,\n  ]\n};\n"
  },
  {
    "path": ".config/factory.js",
    "content": "import { baseConfig } from './base';\nimport { cjsConfig } from './commonjs';\nimport { esConfig } from './es';\nimport { umdConfig } from './umd';\nimport { minConfig } from './minified';\n\nexport function createConfig() {\n  const env = process.env.NODE_ENV;\n  const config = baseConfig;\n  const newConfigs = {\n    cjs: cjsConfig,\n    es: esConfig,\n    umd: umdConfig,\n    min: minConfig,\n  };\n  const newConfig = newConfigs[env];\n\n  for (let key in newConfig) {\n    if (newConfig.hasOwnProperty(key)) {\n      if (Array.isArray(config[key]) && Array.isArray(newConfig[key])) {\n        config[key] = newConfig[key];\n\n      } else if (typeof config[key] === 'object' && typeof newConfig[key] === 'object') {\n        Object.assign(config[key], newConfig[key]);\n\n      } else {\n        config[key] = newConfig[key];\n      }\n    }\n  }\n\n  return config;\n}\n"
  },
  {
    "path": ".config/helpers/licenseBanner.js",
    "content": "export function addLicenseBanner(config) {\n  const path = require('path');\n  const fs = require('fs');\n  const packageBody = require(`./package.json`);\n\n  let licenseBody = fs.readFileSync(path.resolve(__dirname, './LICENSE'), 'utf8');\n  licenseBody += `\\nVersion: ${packageBody.version} (built at ${new Date().toString()})`;\n\n  config.output.banner = `/*!\\n${licenseBody.replace(/^/gm, ' * ')}\\n */`;\n\n  return config;\n}\n"
  },
  {
    "path": ".config/minified.js",
    "content": "import { baseConfig } from './base';\nimport { addLicenseBanner } from './helpers/licenseBanner';\nimport replace from 'rollup-plugin-replace';\nimport { uglify } from 'rollup-plugin-uglify';\n\nconst minFilename = 'react-handsontable.min.js';\n\nconst minConfig = {\n  output: {\n    format: 'umd',\n    name: 'Handsontable.react',\n    indent: false,\n    sourcemap: true,\n    exports: 'named',\n    file: `./dist/${minFilename}`,\n    globals: {\n      react: 'React',\n      'react-dom': 'ReactDOM',\n      handsontable: 'Handsontable'\n    }\n  },\n  plugins: baseConfig.plugins.concat([\n    replace({\n      'process.env.NODE_ENV': JSON.stringify('production')\n    }),\n    uglify({\n      output: {\n        comments: /^!/\n      },\n      compress: {\n        pure_getters: true,\n        unsafe: true,\n        unsafe_comps: true,\n      }\n    })\n  ])\n};\n\naddLicenseBanner(minConfig);\n\nexport { minConfig };\n"
  },
  {
    "path": ".config/umd.js",
    "content": "import { addLicenseBanner } from './helpers/licenseBanner';\nimport { baseConfig } from './base';\nimport replace from 'rollup-plugin-replace';\n\nconst env = process.env.NODE_ENV;\nconst filename = 'react-handsontable.js';\n\nconst umdConfig = {\n  output: {\n    format: env,\n    name: 'Handsontable.react',\n    indent: false,\n    sourcemap: true,\n    exports: 'named',\n    file: `./dist/${filename}`,\n    globals: {\n      react: 'React',\n      'react-dom': 'ReactDOM',\n      handsontable: 'Handsontable'\n    }\n  },\n  plugins: baseConfig.plugins.concat([\n    replace({\n      'process.env.NODE_ENV': JSON.stringify('production')\n    })\n  ])\n};\n\naddLicenseBanner(umdConfig);\n\nexport { umdConfig };\n"
  },
  {
    "path": ".editorconfig",
    "content": "[*]\nindent_style = space\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "### Description\n<!--- Tell us what happens and what should happen -->\n\n### Steps to reproduce\n<!--- Provide steps to reproduce this issue -->\n1.\n2.\n3.\n\n### Demo\n<!--- Provide a link to a live example on JSFiddle or Codepen or fill the following demo with your settings -->\nhttps://jsfiddle.net/handsoncode/c6rgz08x/\n\n### Your environment\n* React wrapper version:\n* Handsontable version:\n* Browser Name and version:\n* Operating System:\n\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "### Context\n<!--- Why is this change required? What problem does it solve? -->\n\n### How has this been tested?\n<!--- Please describe in detail how you tested your changes. -->\n\n### Types of changes\n<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->\n- [ ] Bug fix (non-breaking change which fixes an issue)\n- [ ] New feature or improvement (non-breaking change which adds functionality)\n- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)\n\n### Related issue(s):\n1.\n2.\n3.\n\n### Checklist:\n<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->\n<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->\n- [ ] My code follows the code style of this project,\n- [ ] My change requires a change to the documentation.\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\nbower_components\ndist\ncommonjs\nes\n\n.DS_Store\n.idea\n.rpt2_cache\n*.log\n/*.d.ts\n"
  },
  {
    "path": ".npmignore",
    "content": "*\n\n!commonjs/*\n!dist/*\n!es/*\n!package.json\n!*.d.ts\n!README.md\n!LICENSE\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\n\nsudo: false\n\nnode_js:\n  - '8'\n\nbefore_script:\n  - export TZ=Europe/Warsaw\n\nnotifications:\n  email: false\n  slack:\n    secure: cDGwvetvROdzjr+rM8KYU48ZQNNwoyeSDI5KnH0y8jrGj/KhbHOsoToNjensduI3afoyouRKc1rbxe7qfmikT0SSiJluyWM4VwXRkdye0I0POnLYISS/fTPFGDulFyiuxOhHzmiQav1+zNkYonGgOVBVt/NqTZkSdc/n6HNdKXIC+3KLdUQ3AI+eaoPaph4jqUdaojSQr26K49Y8us/F7ITI7pPyxG/aVLzLwobGeUaYho+R3PahYBnPlhzNIpeAQ98ZM0Dv4+3ZLzkOZi+/qKWTsaOYFpAlm41QohrcN47XtBCDVLxZ9UzEghkIfHJS68po1MuBDK+ULgm7+LkwEMd6/iTJsKa7ziVmY5ijXdFIc4i+kfMjwsQO7Fm5XAVpm66O+qXlRG5cveCEuLl2NEGBsZ/6caKD7AOqWzF2X5UL+O3qX0deWLT4AOnS/nGnlysPr94/Pthy2QMTt8/lqxpMtBEH9zy0mM7l1ZbeL/eDgUGzNXHxS0rpaE873Ea9Kaq4PZ20AISTGlni11gZbhpAOWhjl9X4sbXzk8ANTvnTf/CeYX8JXCuTEXPPLr4WkHS+1oSq4rfA7DNKrqMgs1LceIy07GogtgAGhJx2b1jFsvk8rO7G0/wOC+E1SIM/8NzQkRxpRmS8y2jkJ4BaQM/6Ee4lpNocC1fsG2VhCw4=\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to Handsontable\n\nYour contributions to this project are very welcome. If you want to fix a bug or propose a new feature, you can open a new Pull Request but first make sure it follows these general rules:\n\n1. Sign this [Contributor License Agreement](https://goo.gl/forms/yuutGuN0RjsikVpM2) to allow us to publish your changes to the code.\n2. Make your changes on a separate branch. This will speed up the merging process.\n3. Always make the target of your pull request the `develop` branch, not `master`.\n4. Please review our [coding style](https://github.com/airbnb/javascript) for instructions on how to properly style the code.\n5. Add a thorough description of all the changes.\n\nThank you for your commitment!\n"
  },
  {
    "path": "LICENSE",
    "content": "(The MIT License)\n\nCopyright (c) Handsoncode sp. z o.o. <hello@handsoncode.net>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\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 OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Important information\n\n## We permanently moved this project to the main Handsontable repository at [https://github.com/handsontable/handsontable/tree/master/wrappers/react](https://github.com/handsontable/handsontable/tree/master/wrappers/react)\n\n## It is still available under the same name in npm: [`@handsontable/react`](https://www.npmjs.com/package/@handsontable/react), so you don't have to update your dependency configuration.\n\n---------\n<br><br><br>\n\n<div align=\"center\">\n  \n![Handsontable for React](https://raw.githubusercontent.com/handsontable/static-files/master/Images/Logo/Handsontable/handsontable-react.png)\n\nThis is the official wrapper of [**Handsontable**](//github.com/handsontable/handsontable) data grid for React.<br>\nIt provides data binding, data validation, filtering, sorting and more.<br>\n\n[![npm](https://img.shields.io/npm/dt/@handsontable/react.svg)](//npmjs.com/package/@handsontable/react)\n[![npm](https://img.shields.io/npm/dm/@handsontable/react.svg)](//npmjs.com/package/@handsontable/react)\n[![Build status](https://travis-ci.org/handsontable/react-handsontable.png?branch=master)](//travis-ci.org/handsontable/react-handsontable)\n</div>\n\n<br>\n\n<div align=\"center\">\n<a href=\"//handsontable.com/docs/frameworks-wrapper-for-react-simple-examples.html\">\n<img src=\"https://raw.githubusercontent.com/handsontable/static-files/master/Images/Screenshots/handsontable-screenshot-new.png\" align=\"center\" alt=\"A screenshot of a data grid for React\"/>\n</a>\n</div>\n\n<br>\n\n## Installation\n\nUse npm to install this wrapper together with Handsontable.\n```\nnpm install handsontable @handsontable/react\n```\n\nYou can load it directly from [jsDelivr](//jsdelivr.com/package/npm/@handsontable/react) as well.\n```html\n<script src=\"https://cdn.jsdelivr.net/npm/handsontable/dist/handsontable.full.min.js\"></script>\n<script src=\"https://cdn.jsdelivr.net/npm/@handsontable/react/dist/react-handsontable.min.js\"></script>\n\n<link href=\"https://cdn.jsdelivr.net/npm/handsontable/dist/handsontable.full.min.css\" rel=\"stylesheet\">\n```\n\nThe component will be available as `Handsontable.react.HotTable`.\n\n## Usage\n\nUse this data grid as you would any other component in your application. [Options](//handsontable.com/docs/Options.html) can be set as `HotTable` props.\n\n**Styles**\n```css\n@import '~handsontable/dist/handsontable.full.css';\n```\n\n**React Component**\n```js\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport { HotTable } from '@handsontable/react';\n\nclass HotApp extends React.Component {\n  constructor(props) {\n    super(props);\n    this.data = [\n      ['', 'Tesla', 'Mercedes', 'Toyota', 'Volvo'],\n      ['2019', 10, 11, 12, 13],\n      ['2020', 20, 11, 14, 13],\n      ['2021', 30, 15, 12, 13]\n    ];\n  }\n\n  render() {\n    return (<HotTable data={this.data} colHeaders={true} rowHeaders={true} width=\"600\" height=\"300\" />);\n  }\n}\n```\n\n##### [See the live demo](//handsontable.com/docs/frameworks-wrapper-for-react-simple-examples.html)\n\n## Features\n\nA list of some of the most popular features:\n\n- Multiple column sorting\n- Non-contiguous selection\n- Filtering data\n- Export to file\n- Validating data\n- Conditional formatting\n- Merging cells\n- Custom cell types\n- Freezing rows/columns\n- Moving rows/columns\n- Resizing rows/columns\n- Hiding rows/columns\n- Context menu\n- Comments\n- Auto-fill option\n\n## Documentation\n\n- [Developer guides](//handsontable.com/docs/react)\n- [API Reference](//handsontable.com/docs/Core.html)\n- [Release notes](//handsontable.com/docs/tutorial-release-notes.html)\n- [Twitter](//twitter.com/handsontable) (News and updates)\n\n## Support and contribution\n\nWe provide support for all users through [GitHub issues](//github.com/handsontable/react-handsontable/issues). If you have a commercial license then you can add a new ticket through the [contact form](//handsontable.com/contact?category=technical_support).\n\nIf you would like to contribute to this project, make sure you first read the [guide for contributors](//github.com/handsontable/react-handsontable/blob/master/CONTRIBUTING.md).\n\n## Browser compatibility\n\nHandsontable is compatible with modern browsers such as Chrome, Firefox, Safari, Opera, and Edge. It also supports Internet Explorer 9 to 11 but with limited performance.\n\n## License\n\nThis wrapper is released under [the MIT license](//github.com/handsontable/react-handsontable/blob/master/LICENSE) but under the hood it uses [Handsontable](//github.com/handsontable/handsontable), which is dual-licensed. You can either use it for free in all your non-commercial projects or purchase a commercial license.\n\n<table>\n  <thead align=\"center\">\n    <tr>\n      <th width=\"50%\">Free license</th>\n      <th width=\"50%\">Paid license</th>\n    </tr>    \n  </thead>\n  <tbody align=\"center\">\n    <tr>\n      <td>For non-commercial purposes such as teaching, academic research, personal experimentation, and evaluating  on development and testing servers.</td>\n      <td>For all commercial purposes</td>\n    </tr>\n    <tr>\n      <td>All features are available</td>\n      <td>All features are available</td>\n    </tr>\n    <tr>\n      <td>Community support</td>\n      <td>Dedicated support</td>\n    </tr>    \n    <tr>\n      <td><a href=\"//github.com/handsontable/handsontable/blob/master/handsontable-non-commercial-license.pdf\">Read the license</a></td>\n      <td><a href=\"//handsontable.com/pricing\">See plans</a></td>\n    </tr>\n  </tbody>\n</table>\n\n## License key\n\n**The license key is obligatory since [Handsontable 7.0.0](//github.com/handsontable/handsontable/releases/tag/7.0.0) (released in March 2019).**\n\nIf you use Handsontable for purposes not intended toward monetary compensation such as, but not limited to, teaching, academic research, evaluation, testing and experimentation, pass a phrase `'non-commercial-and-evaluation'`, as presented below. \n\nYou can pass it in the `settings` object: \n\n```js\nsettings: {\n  data: data,\n  rowHeaders: true,\n  colHeaders: true,\n  licenseKey: 'non-commercial-and-evaluation'\n}\n```\n\nAlternatively, you can pass it to a `licenseKey` prop:\n\n```jsx\n<HotTable settings={settings} licenseKey=\"00000-00000-00000-00000-00000\" />\n```\n\nIf, on the other hand, you use Handsontable in a project that supports your commercial activity, then you must purchase the license key at [handsontable.com](//handsontable.com/pricing).\n\nThe license key is validated in an offline mode.  No connection is made to any server. [Learn more](//handsontable.com/docs/tutorial-license-key.html) about how it works.\n\n<br>\n<br>\n\nCreated by [Handsoncode](//handsoncode.net) with ❤ and ☕ in [Tricity](//en.wikipedia.org/wiki/Tricity,_Poland).\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@handsontable/react\",\n  \"version\": \"4.0.0\",\n  \"description\": \"Best Data Grid for React with Spreadsheet Look and Feel.\",\n  \"author\": \"Handsoncode <hello@handsoncode.net> (https://handsoncode.net)\",\n  \"homepage\": \"https://handsontable.com\",\n  \"license\": \"MIT\",\n  \"main\": \"./commonjs/react-handsontable.js\",\n  \"module\": \"./es/react-handsontable.js\",\n  \"jsdelivr\": \"./dist/react-handsontable.min.js\",\n  \"unpkg\": \"./dist/react-handsontable.min.js\",\n  \"types\": \"./index.d.ts\",\n  \"keywords\": [\n    \"handsontable\",\n    \"component\",\n    \"grid\",\n    \"data\",\n    \"table\",\n    \"data table\",\n    \"data grid\",\n    \"spreadsheet\",\n    \"sheet\",\n    \"excel\",\n    \"enterprise\",\n    \"sort\",\n    \"formulas\",\n    \"filter\",\n    \"search\",\n    \"conditional\",\n    \"formatting\",\n    \"csv\",\n    \"react\",\n    \"reactjs\",\n    \"react component\",\n    \"react grid\",\n    \"wrapper\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/handsontable/react-handsontable.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/handsontable/react-handsontable/issues\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.8.4\",\n    \"@babel/core\": \"^7.9.0\",\n    \"@babel/plugin-proposal-class-properties\": \"^7.8.3\",\n    \"@babel/plugin-transform-runtime\": \"^7.9.0\",\n    \"@babel/polyfill\": \"^7.8.7\",\n    \"@babel/preset-env\": \"^7.9.0\",\n    \"@babel/preset-react\": \"^7.9.4\",\n    \"@babel/preset-typescript\": \"^7.9.0\",\n    \"@babel/runtime\": \"^7.9.2\",\n    \"@types/enzyme\": \"^3.1.15\",\n    \"@types/enzyme-adapter-react-16\": \"^1.0.3\",\n    \"@types/jest\": \"^24.0.9\",\n    \"@types/react\": \"^16.9.5\",\n    \"@types/react-dom\": \"^16.9.1\",\n    \"@types/react-redux\": \"^7.1.7\",\n    \"babel-core\": \"^7.0.0-bridge.0\",\n    \"cpy-cli\": \"^3.1.1\",\n    \"cross-env\": \"^5.2.0\",\n    \"del-cli\": \"^3.0.1\",\n    \"enzyme\": \"^3.10.0\",\n    \"enzyme-adapter-react-16\": \"^1.14.0\",\n    \"enzyme-to-json\": \"^3.4.0\",\n    \"handsontable\": \"^8.0.0\",\n    \"jest\": \"^25.1.0\",\n    \"prop-types\": \"^15.7.2\",\n    \"react\": \"^16.10.2\",\n    \"react-dom\": \"^16.10.2\",\n    \"react-redux\": \"^7.1.1\",\n    \"redux\": \"^4.0.4\",\n    \"rollup\": \"^1.17.0\",\n    \"rollup-plugin-alias\": \"^1.5.2\",\n    \"rollup-plugin-babel\": \"^4.3.3\",\n    \"rollup-plugin-commonjs\": \"^10.0.1\",\n    \"rollup-plugin-json\": \"^4.0.0\",\n    \"rollup-plugin-node-resolve\": \"^5.2.0\",\n    \"rollup-plugin-replace\": \"^2.2.0\",\n    \"rollup-plugin-typescript2\": \"^0.22.1\",\n    \"rollup-plugin-uglify\": \"^6.0.4\",\n    \"typescript\": \"^3.5.3\",\n    \"uglify-js\": \"^3.4.9\"\n  },\n  \"peerDependencies\": {\n    \"handsontable\": \">=8.0.0\"\n  },\n  \"scripts\": {\n    \"build\": \"npm run delete-build && npm run build:commonjs && npm run build:es && npm run build:umd && npm run build:min\",\n    \"build:commonjs\": \"cross-env NODE_ENV=cjs rollup -c\",\n    \"build:umd\": \"cross-env NODE_ENV=umd rollup -c\",\n    \"build:es\": \"cross-env NODE_ENV=es rollup -c\",\n    \"build:min\": \"cross-env NODE_ENV=min rollup -c\",\n    \"delete-build\": \"del-cli ./es/ && del-cli ./commonjs/ && del-cli ./dist/ && del-cli ./*.d.ts\",\n    \"publish-build\": \"npm publish\",\n    \"publish-all\": \"npm run build && npm run publish-build && npm run delete-build\",\n    \"test\": \"jest\",\n    \"watch:commonjs\": \"cross-env NODE_ENV=cjs rollup -c --watch\",\n    \"watch:es\": \"cross-env NODE_ENV=es rollup -c --watch\"\n  },\n  \"jest\": {\n    \"testURL\": \"http://localhost/\",\n    \"setupFiles\": [\n      \"./test/jestsetup.ts\"\n    ],\n    \"snapshotSerializers\": [\n      \"enzyme-to-json/serializer\"\n    ],\n    \"transform\": {\n      \"^.+\\\\.tsx?$\": \"babel-jest\",\n      \"^.+\\\\.js$\": \"babel-jest\"\n    },\n    \"testRegex\": \"(/test/(.*).(test|spec)).(jsx?|tsx?)$\",\n    \"moduleFileExtensions\": [\n      \"ts\",\n      \"tsx\",\n      \"js\",\n      \"jsx\",\n      \"json\",\n      \"node\"\n    ],\n    \"globals\": {\n      \"ts-jest\": {\n        \"tsConfig\": \"test-tsconfig.json\",\n        \"babelConfig\": true\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "rollup.config.js",
    "content": "import { createConfig } from './.config/factory';\n\nexport default createConfig();\n"
  },
  {
    "path": "src/baseEditorComponent.tsx",
    "content": "import React from 'react';\nimport Handsontable from 'handsontable';\nimport { HotEditorProps } from './types';\n\nclass BaseEditorComponent<P = {}, S = {}, SS = any> extends React.Component<P | HotEditorProps, S> implements Handsontable._editors.Base {\n  name = 'BaseEditorComponent';\n  instance = null;\n  row = null;\n  col = null;\n  prop = null;\n  TD = null;\n  originalValue = null;\n  cellProperties = null;\n  state = null;\n  hotInstance = null;\n  hotCustomEditorInstance = null;\n  hot = null;\n\n  constructor(props) {\n    super(props);\n\n    if (props.emitEditorInstance) {\n      props.emitEditorInstance(this);\n    }\n  }\n\n  // BaseEditor methods:\n  private _fireCallbacks(...args) {\n    (Handsontable.editors.BaseEditor.prototype as any)._fireCallbacks.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  beginEditing(...args) {\n    return Handsontable.editors.BaseEditor.prototype.beginEditing.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  cancelChanges(...args) {\n    return Handsontable.editors.BaseEditor.prototype.cancelChanges.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  checkEditorSection(...args) {\n    return Handsontable.editors.BaseEditor.prototype.checkEditorSection.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  close(...args) {\n    return Handsontable.editors.BaseEditor.prototype.close.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  discardEditor(...args) {\n    return Handsontable.editors.BaseEditor.prototype.discardEditor.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  enableFullEditMode(...args) {\n    return Handsontable.editors.BaseEditor.prototype.enableFullEditMode.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  extend(...args) {\n    return Handsontable.editors.BaseEditor.prototype.extend.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  finishEditing(...args) {\n    return Handsontable.editors.BaseEditor.prototype.finishEditing.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  focus(...args) {\n    return Handsontable.editors.BaseEditor.prototype.focus.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  getValue(...args) {\n    return Handsontable.editors.BaseEditor.prototype.getValue.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  init(...args) {\n    return Handsontable.editors.BaseEditor.prototype.init.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  isInFullEditMode(...args) {\n    return Handsontable.editors.BaseEditor.prototype.isInFullEditMode.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  isOpened(...args) {\n    return Handsontable.editors.BaseEditor.prototype.isOpened.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  isWaiting(...args) {\n    return Handsontable.editors.BaseEditor.prototype.isWaiting.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  open(...args) {\n    return Handsontable.editors.BaseEditor.prototype.open.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  prepare(row, col, prop, TD, originalValue, cellProperties) {\n    this.hotInstance = cellProperties.instance;\n    this.row = row;\n    this.col = col;\n    this.prop = prop;\n    this.TD = TD;\n    this.originalValue = originalValue;\n    this.cellProperties = cellProperties;\n\n    return Handsontable.editors.BaseEditor.prototype.prepare.call(this.hotCustomEditorInstance, row, col, prop, TD, originalValue, cellProperties);\n  }\n\n  saveValue(...args) {\n    return Handsontable.editors.BaseEditor.prototype.saveValue.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  setValue(...args) {\n    return Handsontable.editors.BaseEditor.prototype.setValue.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  addHook(...args) {\n    return (Handsontable.editors.BaseEditor.prototype as any).addHook.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  removeHooksByKey(...args) {\n    return (Handsontable.editors.BaseEditor.prototype as any).removeHooksByKey.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  clearHooks(...args) {\n    return (Handsontable.editors.BaseEditor.prototype as any).clearHooks.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  getEditedCell(...args) {\n    return (Handsontable.editors.BaseEditor.prototype as any).getEditedCell.call(this.hotCustomEditorInstance, ...args);\n  }\n\n  getEditedCellsZIndex(...args) {\n    return (Handsontable.editors.BaseEditor.prototype as any).getEditedCellsZIndex.call(this.hotCustomEditorInstance, ...args);\n  }\n}\n\nexport default BaseEditorComponent;\nexport { BaseEditorComponent };\n"
  },
  {
    "path": "src/helpers.tsx",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport { HotEditorElement } from './types';\n\nlet bulkComponentContainer = null;\n\n/**\n * Warning message for the `autoRowSize`/`autoColumnSize` compatibility check.\n */\nexport const AUTOSIZE_WARNING = 'Your `HotTable` configuration includes `autoRowSize`/`autoColumnSize` options, which are not compatible with ' +\n  ' the component-based renderers`. Disable `autoRowSize` and `autoColumnSize` to prevent row and column misalignment.';\n\n/**\n * Default classname given to the wrapper container.\n */\nconst DEFAULT_CLASSNAME = 'hot-wrapper-editor-container';\n\n/**\n * Logs warn to the console if the `console` object is exposed.\n *\n * @param {...*} args Values which will be logged.\n */\nexport function warn(...args) {\n  if (typeof console !== 'undefined') {\n    console.warn(...args);\n  }\n}\n\n/**\n * Filter out and return elements of the provided `type` from the `HotColumn` component's children.\n *\n * @param {React.ReactNode} children HotTable children array.\n * @param {String} type Either `'hot-renderer'` or `'hot-editor'`.\n * @returns {Object|null} A child (React node) or `null`, if no child of that type was found.\n */\nexport function getChildElementByType(children: React.ReactNode, type: string): React.ReactElement | null {\n  const childrenArray: React.ReactNode[] = React.Children.toArray(children);\n  const childrenCount: number = React.Children.count(children);\n  let wantedChild: React.ReactNode | null = null;\n\n  if (childrenCount !== 0) {\n    if (childrenCount === 1 && (childrenArray[0] as React.ReactElement).props[type]) {\n      wantedChild = childrenArray[0];\n\n    } else {\n      wantedChild = childrenArray.find((child) => {\n        return (child as React.ReactElement).props[type] !== void 0;\n      });\n    }\n  }\n\n  return (wantedChild as React.ReactElement) || null;\n}\n\n/**\n * Get the reference to the original editor class.\n *\n * @param {React.ReactElement} editorElement React element of the editor class.\n * @returns {Function} Original class of the editor component.\n */\nexport function getOriginalEditorClass(editorElement: HotEditorElement) {\n  if (!editorElement) {\n    return null;\n  }\n\n  return editorElement.type.WrappedComponent ? editorElement.type.WrappedComponent : editorElement.type;\n}\n\n/**\n * Remove editor containers from DOM.\n *\n * @param {Document} [doc] Document to be used.\n * @param {Map} editorCache The editor cache reference.\n */\nexport function removeEditorContainers(doc = document): void {\n  doc.querySelectorAll(`[class^=\"${DEFAULT_CLASSNAME}\"]`).forEach((domNode) => {\n    if (domNode.parentNode) {\n      domNode.parentNode.removeChild(domNode);\n    }\n  });\n}\n\n/**\n * Create an editor portal.\n *\n * @param {Document} [doc] Document to be used.\n * @param {React.ReactElement} editorElement Editor's element.\n * @param {Map} editorCache The editor cache reference.\n * @returns {React.ReactPortal} The portal for the editor.\n */\nexport function createEditorPortal(doc = document, editorElement: HotEditorElement, editorCache: Map<Function, React.Component>): React.ReactPortal {\n  if (editorElement === null) {\n    return;\n  }\n\n  const editorContainer = doc.createElement('DIV');\n  const {id, className, style} = getContainerAttributesProps(editorElement.props, false);\n\n  if (id) {\n    editorContainer.id = id;\n  }\n\n  editorContainer.className = [DEFAULT_CLASSNAME, className].join(' ');\n\n  if (style) {\n    Object.assign(editorContainer.style, style);\n  }\n\n  doc.body.appendChild(editorContainer);\n\n  return ReactDOM.createPortal(editorElement, editorContainer);\n}\n\n/**\n * Get an editor element extended with a instance-emitting method.\n *\n * @param {React.ReactNode} children Component children.\n * @param {Map} editorCache Component's editor cache.\n * @returns {React.ReactElement} An editor element containing the additional methods.\n */\nexport function getExtendedEditorElement(children: React.ReactNode, editorCache: Map<Function, object>): React.ReactElement | null {\n  const editorElement = getChildElementByType(children, 'hot-editor');\n  const editorClass = getOriginalEditorClass(editorElement);\n\n  if (!editorElement) {\n    return null;\n  }\n\n  return React.cloneElement(editorElement, {\n    emitEditorInstance: (editorInstance) => {\n      editorCache.set(editorClass, editorInstance);\n    },\n    isEditor: true\n  } as object);\n}\n\n/**\n * Create a react component and render it to an external DOM done.\n *\n * @param {React.ReactElement} rElement React element to be used as a base for the component.\n * @param {Object} props Props to be passed to the cloned element.\n * @param {Function} callback Callback to be called after the component has been mounted.\n * @param {Document} [ownerDocument] The owner document to set the portal up into.\n * @returns {{portal: React.ReactPortal, portalContainer: HTMLElement}} An object containing the portal and its container.\n */\nexport function createPortal(rElement: React.ReactElement, props, callback: Function, ownerDocument: Document = document): {\n  portal: React.ReactPortal,\n  portalContainer: HTMLElement\n} {\n  if (!ownerDocument) {\n    ownerDocument = document;\n  }\n\n  if (!bulkComponentContainer) {\n    bulkComponentContainer = ownerDocument.createDocumentFragment();\n  }\n\n  const portalContainer = ownerDocument.createElement('DIV');\n  bulkComponentContainer.appendChild(portalContainer);\n\n  const extendedRendererElement = React.cloneElement(rElement, {\n    key: `${props.row}-${props.col}`,\n    ...props\n  });\n\n  return {\n    portal: ReactDOM.createPortal(extendedRendererElement, portalContainer, `${props.row}-${props.col}-${Math.random()}`),\n    portalContainer\n  };\n}\n\n/**\n * Get an object containing the `id`, `className` and `style` keys, representing the corresponding props passed to the\n * component.\n *\n * @param {Object} props Object containing the react element props.\n * @param {Boolean} randomizeId If set to `true`, the function will randomize the `id` property when no `id` was present in the `prop` object.\n * @returns An object containing the `id`, `className` and `style` keys, representing the corresponding props passed to the\n * component.\n */\nexport function getContainerAttributesProps(props, randomizeId: boolean = true): {id: string, className: string, style: object} {\n  return {\n    id: props.id || (randomizeId ? 'hot-' + Math.random().toString(36).substring(5) : void 0),\n    className: props.className || '',\n    style: props.style || {},\n  }\n}\n\n/**\n * Add the `UNSAFE_` prefixes to the deprecated lifecycle methods for React >= 16.3.\n *\n * @param {Object} instance Instance to have the methods renamed.\n */\nexport function addUnsafePrefixes(instance: {\n  UNSAFE_componentWillUpdate?: Function,\n  componentWillUpdate: Function,\n  UNSAFE_componentWillMount?: Function,\n  componentWillMount: Function\n}): void {\n  const reactSemverArray = React.version.split('.').map((v) => parseInt(v));\n  const shouldPrefix = reactSemverArray[0] >= 16 && reactSemverArray[1] >= 3;\n\n  if (shouldPrefix) {\n    instance.UNSAFE_componentWillUpdate = instance.componentWillUpdate;\n    instance.componentWillUpdate = void 0;\n\n    instance.UNSAFE_componentWillMount = instance.componentWillMount;\n    instance.componentWillMount = void 0;\n  }\n}\n"
  },
  {
    "path": "src/hotColumn.tsx",
    "content": "import React, { ReactPortal } from 'react';\nimport { HotTableProps, HotColumnProps } from './types';\nimport {\n  addUnsafePrefixes,\n  createEditorPortal,\n  getExtendedEditorElement\n} from './helpers';\nimport { SettingsMapper } from './settingsMapper';\nimport Handsontable from 'handsontable';\n\nclass HotColumn extends React.Component<HotColumnProps, {}> {\n  internalProps: string[];\n  columnSettings: Handsontable.GridSettings;\n\n  /**\n   * Local editor portal cache.\n   *\n   * @private\n   * @type {ReactPortal}\n   */\n  private localEditorPortal: ReactPortal = null;\n\n  /**\n   * HotColumn class constructor.\n   *\n   * @param {HotColumnProps} props Component props.\n   * @param {*} [context] Component context.\n   */\n  constructor(props: HotColumnProps, context?: any) {\n    super(props, context);\n\n    addUnsafePrefixes(this);\n  }\n\n  /**\n   * Get the local editor portal cache property.\n   *\n   * @return {ReactPortal} Local editor portal.\n   */\n  getLocalEditorPortal(): ReactPortal {\n    return this.localEditorPortal;\n  }\n\n  /**\n   * Set the local editor portal cache property.\n   *\n   * @param {ReactPortal} portal Local editor portal.\n   */\n  setLocalEditorPortal(portal): void {\n    this.localEditorPortal = portal;\n  }\n\n  /**\n   * Filter out all the internal properties and return an object with just the Handsontable-related props.\n   *\n   * @returns {Object}\n   */\n  getSettingsProps(): HotTableProps {\n    this.internalProps = ['__componentRendererColumns', '_emitColumnSettings', '_columnIndex', '_getChildElementByType', '_getRendererWrapper',\n      '_getEditorClass', '_getEditorCache', '_getOwnerDocument', 'hot-renderer', 'hot-editor', 'children'];\n\n    return Object.keys(this.props)\n      .filter(key => {\n        return !this.internalProps.includes(key);\n      })\n      .reduce((obj, key) => {\n        obj[key] = this.props[key];\n\n        return obj;\n      }, {});\n  }\n\n  /**\n   * Check whether the HotColumn component contains a provided prop.\n   *\n   * @param {String} propName Property name.\n   * @returns {Boolean}\n   */\n  hasProp(propName: string): boolean {\n    return !!this.props[propName];\n  }\n\n  /**\n   * Get the editor element for the current column.\n   *\n   * @returns {React.ReactElement} React editor component element.\n   */\n  getLocalEditorElement(): React.ReactElement | null {\n    return getExtendedEditorElement(this.props.children, this.props._getEditorCache());\n  }\n\n  /**\n   * Create the column settings based on the data provided to the `HotColumn` component and it's child components.\n   */\n  createColumnSettings(): void {\n    const rendererElement: React.ReactElement = this.props._getChildElementByType(this.props.children, 'hot-renderer');\n    const editorElement: React.ReactElement = this.getLocalEditorElement();\n\n    this.columnSettings = SettingsMapper.getSettings(this.getSettingsProps());\n\n    if (rendererElement !== null) {\n      this.columnSettings.renderer = this.props._getRendererWrapper(rendererElement);\n      this.props._componentRendererColumns.set(this.props._columnIndex, true);\n\n    } else if (this.hasProp('renderer')) {\n      this.columnSettings.renderer = this.props.renderer;\n\n    } else {\n      this.columnSettings.renderer = void 0;\n    }\n\n    if (editorElement !== null) {\n      this.columnSettings.editor = this.props._getEditorClass(editorElement);\n\n    } else if (this.hasProp('editor')) {\n      this.columnSettings.editor = this.props.editor;\n\n    } else {\n      this.columnSettings.editor = void 0;\n    }\n  }\n\n  /**\n   * Create the local editor portal and its destination HTML element if needed.\n   *\n   * @param {React.ReactNode} [children] Children of the HotTable instance. Defaults to `this.props.children`.\n   */\n  createLocalEditorPortal(children = this.props.children): void {\n    const editorCache = this.props._getEditorCache();\n    const localEditorElement: React.ReactElement = getExtendedEditorElement(children, editorCache);\n\n    if (localEditorElement) {\n      this.setLocalEditorPortal(createEditorPortal(this.props._getOwnerDocument(), localEditorElement, editorCache));\n    }\n  }\n\n  /**\n   * Emit the column settings to the parent using a prop passed from the parent.\n   */\n  emitColumnSettings(): void {\n    this.props._emitColumnSettings(this.columnSettings, this.props._columnIndex);\n  }\n\n  /*\n  ---------------------------------------\n  ------- React lifecycle methods -------\n  ---------------------------------------\n  */\n\n  /**\n   * Logic performed before the mounting of the HotColumn component.\n   */\n  componentWillMount(): void {\n    this.createLocalEditorPortal();\n  }\n\n  /**\n   * Logic performed after the mounting of the HotColumn component.\n   */\n  componentDidMount(): void {\n    this.createColumnSettings();\n    this.emitColumnSettings();\n  }\n\n  /**\n   * Logic performed before the updating of the HotColumn component.\n   */\n  componentWillUpdate(nextProps: Readonly<HotColumnProps>, nextState: Readonly<{}>, nextContext: any): void {\n    this.createLocalEditorPortal(nextProps.children);\n  }\n\n  /**\n   * Logic performed after the updating of the HotColumn component.\n   */\n  componentDidUpdate(): void {\n    this.createColumnSettings();\n    this.emitColumnSettings();\n  }\n\n  /**\n   * Render the portals of the editors, if there are any.\n   *\n   * @returns {React.ReactElement}\n   */\n  render(): React.ReactElement {\n    return (\n      <React.Fragment>\n        {this.getLocalEditorPortal()}\n      </React.Fragment>\n    )\n  }\n}\n\nexport { HotColumn };\n"
  },
  {
    "path": "src/hotTable.tsx",
    "content": "import React from 'react';\nimport Handsontable from 'handsontable';\nimport { SettingsMapper } from './settingsMapper';\nimport { PortalManager } from './portalManager';\nimport { HotColumn } from './hotColumn';\nimport * as packageJson from '../package.json';\nimport {\n  HotTableProps,\n  HotEditorElement\n} from './types';\nimport {\n  AUTOSIZE_WARNING,\n  createEditorPortal,\n  createPortal,\n  getChildElementByType,\n  getContainerAttributesProps,\n  getExtendedEditorElement,\n  getOriginalEditorClass,\n  addUnsafePrefixes,\n  removeEditorContainers,\n  warn\n} from './helpers';\nimport PropTypes from 'prop-types';\n\n/**\n * A Handsontable-ReactJS wrapper.\n *\n * To implement, use the `HotTable` tag with properties corresponding to Handsontable options.\n * For example:\n *\n * ```js\n * <HotTable id=\"hot\" data={dataObject} contextMenu={true} colHeaders={true} width={600} height={300} stretchH=\"all\" />\n *\n * // is analogous to\n * let hot = new Handsontable(document.getElementById('hot'), {\n *    data: dataObject,\n *    contextMenu: true,\n *    colHeaders: true,\n *    width: 600\n *    height: 300\n * });\n *\n * ```\n *\n * @class HotTable\n */\nclass HotTable extends React.Component<HotTableProps, {}> {\n  /**\n   * The `id` of the main Handsontable DOM element.\n   *\n   * @type {String}\n   */\n  id: string = null;\n  /**\n   * Reference to the Handsontable instance.\n   *\n   * @type {Object}\n   */\n  hotInstance: Handsontable = null;\n  /**\n   * Reference to the main Handsontable DOM element.\n   *\n   * @type {HTMLElement}\n   */\n  hotElementRef: HTMLElement = null;\n  /**\n   * Class name added to the component DOM element.\n   *\n   * @type {String}\n   */\n  className: string;\n  /**\n   * Style object passed to the component.\n   *\n   * @type {React.CSSProperties}\n   */\n  style: React.CSSProperties;\n\n  /**\n   * Array of object containing the column settings.\n   *\n   * @type {Array}\n   */\n  columnSettings: Handsontable.ColumnSettings[] = [];\n\n  /**\n   * Component used to manage the renderer portals.\n   *\n   * @type {React.Component}\n   */\n  portalManager: PortalManager = null;\n\n  /**\n   * Array containing the portals cashed to be rendered in bulk after Handsontable's render cycle.\n   */\n  portalCacheArray: React.ReactPortal[] = [];\n\n  /**\n   * Global editor portal cache.\n   *\n   * @private\n   * @type {React.ReactPortal}\n   */\n  private globalEditorPortal: React.ReactPortal = null;\n\n  /**\n   * The rendered cells cache.\n   *\n   * @private\n   * @type {Map}\n   */\n  private renderedCellCache: Map<string, HTMLTableCellElement> = new Map();\n\n  /**\n   * Editor cache.\n   *\n   * @private\n   * @type {Map}\n   */\n  private editorCache: Map<Function, React.Component> = new Map();\n\n  /**\n   * Map with column indexes (or a string = 'global') as keys, and booleans as values. Each key represents a component-based editor\n   * declared for the used column index, or a global one, if the key is the `global` string.\n   *\n   * @private\n   * @type {Map}\n   */\n  private componentRendererColumns: Map<number | string, boolean> = new Map();\n\n  /**\n   * HotTable class constructor.\n   *\n   * @param {HotTableProps} props Component props.\n   * @param {*} [context] Component context.\n   */\n  constructor(props: HotTableProps, context?: any) {\n    super(props, context);\n\n    addUnsafePrefixes(this);\n  }\n\n  /**\n   * Package version getter.\n   *\n   * @returns The version number of the package.\n   */\n  static get version(): string {\n    return (packageJson as any).version;\n  }\n\n  /**\n   * Prop types to be checked at runtime.\n   */\n  static propTypes: object = {\n    style: PropTypes.object,\n    id: PropTypes.string,\n    className: PropTypes.string\n  };\n\n  /**\n   * Get the rendered table cell cache.\n   *\n   * @returns {Map}\n   */\n  getRenderedCellCache(): Map<string, HTMLTableCellElement> {\n    return this.renderedCellCache;\n  }\n\n  /**\n   * Get the editor cache and return it.\n   *\n   * @returns {Map}\n   */\n  getEditorCache(): Map<Function, React.Component> {\n    return this.editorCache;\n  }\n\n  /**\n   * Get the global editor portal property.\n   *\n   * @return {React.ReactPortal} The global editor portal.\n   */\n  getGlobalEditorPortal(): React.ReactPortal {\n    return this.globalEditorPortal;\n  }\n\n  /**\n   * Set the private editor portal cache property.\n   *\n   * @param {React.ReactPortal} portal Global editor portal.\n   */\n  setGlobalEditorPortal(portal: React.ReactPortal): void {\n    this.globalEditorPortal = portal;\n  }\n\n  /**\n   * Clear both the editor and the renderer cache.\n   */\n  clearCache(): void {\n    const renderedCellCache = this.getRenderedCellCache();\n\n    this.setGlobalEditorPortal(null);\n    removeEditorContainers(this.getOwnerDocument());\n    this.getEditorCache().clear();\n\n    renderedCellCache.clear();\n\n    this.componentRendererColumns.clear();\n  }\n\n  /**\n   * Get the `Document` object corresponding to the main component element.\n   *\n   * @returns The `Document` object used by the component.\n   */\n  getOwnerDocument() {\n    return this.hotElementRef ? this.hotElementRef.ownerDocument : document;\n  }\n\n  /**\n   * Set the reference to the main Handsontable DOM element.\n   *\n   * @param {HTMLElement} element The main Handsontable DOM element.\n   */\n  private setHotElementRef(element: HTMLElement): void {\n    this.hotElementRef = element;\n  }\n\n  /**\n   * Return a renderer wrapper function for the provided renderer component.\n   *\n   * @param {React.ReactElement} rendererElement React renderer component.\n   * @returns {Handsontable.renderers.Base} The Handsontable rendering function.\n   */\n  getRendererWrapper(rendererElement: React.ReactElement): Handsontable.renderers.Base | any {\n    const hotTableComponent = this;\n\n    return function (instance, TD, row, col, prop, value, cellProperties) {\n      const renderedCellCache = hotTableComponent.getRenderedCellCache();\n\n      if (renderedCellCache.has(`${row}-${col}`)) {\n        TD.innerHTML = renderedCellCache.get(`${row}-${col}`).innerHTML;\n      }\n\n      if (TD && !TD.getAttribute('ghost-table')) {\n\n        const {portal, portalContainer} = createPortal(rendererElement, {\n          TD,\n          row,\n          col,\n          prop,\n          value,\n          cellProperties,\n          isRenderer: true\n        }, () => {\n        }, TD.ownerDocument);\n\n        while (TD.firstChild) {\n          TD.removeChild(TD.firstChild);\n        }\n\n        TD.appendChild(portalContainer);\n\n        hotTableComponent.portalCacheArray.push(portal);\n      }\n\n      renderedCellCache.set(`${row}-${col}`, TD);\n\n      return TD;\n    };\n  }\n\n  /**\n   * Create a fresh class to be used as an editor, based on the provided editor React element.\n   *\n   * @param {React.ReactElement} editorElement React editor component.\n   * @returns {Function} A class to be passed to the Handsontable editor settings.\n   */\n  getEditorClass(editorElement: HotEditorElement): typeof Handsontable.editors.BaseEditor {\n    const editorClass = getOriginalEditorClass(editorElement);\n    const editorCache = this.getEditorCache();\n    let cachedComponent: React.Component = editorCache.get(editorClass);\n\n    return this.makeEditorClass(cachedComponent);\n  }\n\n  /**\n   * Create a class to be passed to the Handsontable's settings.\n   *\n   * @param {React.ReactElement} editorComponent React editor component.\n   * @returns {Function} A class to be passed to the Handsontable editor settings.\n   */\n  makeEditorClass(editorComponent: React.Component): typeof Handsontable.editors.BaseEditor {\n    const customEditorClass = class CustomEditor extends Handsontable.editors.BaseEditor implements Handsontable._editors.Base {\n      editorComponent: React.Component;\n\n      constructor(hotInstance, row, col, prop, TD, cellProperties) {\n        super(hotInstance, row, col, prop, TD, cellProperties);\n\n        (editorComponent as any).hotCustomEditorInstance = this;\n\n        this.editorComponent = editorComponent;\n      }\n\n      focus() {\n      }\n\n      getValue() {\n      }\n\n      setValue() {\n      }\n\n      open() {\n      }\n\n      close() {\n      }\n    } as any;\n\n    // Fill with the rest of the BaseEditor methods\n    Object.getOwnPropertyNames(Handsontable.editors.BaseEditor.prototype).forEach(propName => {\n      if (propName === 'constructor') {\n        return;\n      }\n\n      customEditorClass.prototype[propName] = function (...args) {\n        return editorComponent[propName].call(editorComponent, ...args);\n      }\n    });\n\n    return customEditorClass;\n  }\n\n  /**\n   * Get the renderer element for the entire HotTable instance.\n   *\n   * @returns {React.ReactElement} React renderer component element.\n   */\n  getGlobalRendererElement(): React.ReactElement {\n    const hotTableSlots: React.ReactNode = this.props.children;\n\n    return getChildElementByType(hotTableSlots, 'hot-renderer');\n  }\n\n  /**\n   * Get the editor element for the entire HotTable instance.\n   *\n   * @param {React.ReactNode} [children] Children of the HotTable instance. Defaults to `this.props.children`.\n   * @returns {React.ReactElement} React editor component element.\n   */\n  getGlobalEditorElement(children: React.ReactNode = this.props.children): HotEditorElement | null {\n    return getExtendedEditorElement(children, this.getEditorCache());\n  }\n\n  /**\n   * Create the global editor portal and its destination HTML element if needed.\n   *\n   * @param {React.ReactNode} [children] Children of the HotTable instance. Defaults to `this.props.children`.\n   */\n  createGlobalEditorPortal(children: React.ReactNode = this.props.children): void {\n    const globalEditorElement: HotEditorElement = this.getGlobalEditorElement(children);\n\n    if (globalEditorElement) {\n      this.setGlobalEditorPortal(createEditorPortal(this.getOwnerDocument() ,globalEditorElement, this.getEditorCache()))\n    }\n  }\n\n  /**\n   * Create a new settings object containing the column settings and global editors and renderers.\n   *\n   * @returns {Handsontable.GridSettings} New global set of settings for Handsontable.\n   */\n  createNewGlobalSettings(): Handsontable.GridSettings {\n    const newSettings = SettingsMapper.getSettings(this.props);\n    const globalRendererNode = this.getGlobalRendererElement();\n    const globalEditorNode = this.getGlobalEditorElement();\n\n    newSettings.columns = this.columnSettings.length ? this.columnSettings : newSettings.columns;\n\n    if (globalEditorNode) {\n      newSettings.editor = this.getEditorClass(globalEditorNode);\n\n    } else {\n      newSettings.editor = this.props.editor || (this.props.settings ? this.props.settings.editor : void 0);\n    }\n\n    if (globalRendererNode) {\n      newSettings.renderer = this.getRendererWrapper(globalRendererNode);\n      this.componentRendererColumns.set('global', true);\n\n    } else {\n      newSettings.renderer = this.props.renderer || (this.props.settings ? this.props.settings.renderer : void 0);\n    }\n\n    return newSettings;\n  }\n\n  /**\n   * Detect if `autoRowSize` or `autoColumnSize` is defined, and if so, throw an incompatibility warning.\n   *\n   * @param {Handsontable.GridSettings} newGlobalSettings New global settings passed as Handsontable config.\n   */\n  displayAutoSizeWarning(newGlobalSettings: Handsontable.GridSettings): void {\n    if (this.hotInstance.getPlugin('autoRowSize').enabled || this.hotInstance.getPlugin('autoColumnSize').enabled) {\n      if (this.componentRendererColumns.size > 0) {\n        warn(AUTOSIZE_WARNING);\n      }\n    }\n  }\n\n  /**\n   * Sets the column settings based on information received from HotColumn.\n   *\n   * @param {HotTableProps} columnSettings Column settings object.\n   * @param {Number} columnIndex Column index.\n   */\n  setHotColumnSettings(columnSettings: Handsontable.ColumnSettings, columnIndex: number): void {\n    this.columnSettings[columnIndex] = columnSettings;\n  }\n\n  /**\n   * Handsontable's `beforeRender` hook callback.\n   */\n  handsontableBeforeRender(): void {\n    this.getRenderedCellCache().clear();\n  }\n\n  /**\n   * Handsontable's `afterRender` hook callback.\n   */\n  handsontableAfterRender(): void {\n    this.portalManager.setState(() => {\n      return Object.assign({}, {\n        portals: this.portalCacheArray\n      });\n\n    }, () => {\n      this.portalCacheArray.length = 0;\n    });\n  }\n\n  /**\n   * Call the `updateSettings` method for the Handsontable instance.\n   *\n   * @param {Object} newSettings The settings object.\n   */\n  private updateHot(newSettings: Handsontable.GridSettings): void {\n    this.hotInstance.updateSettings(newSettings, false);\n  }\n\n  /**\n   * Set the portal manager ref.\n   *\n   * @param {React.ReactComponent} pmComponent The PortalManager component.\n   */\n  private setPortalManagerRef(pmComponent: PortalManager): void {\n    this.portalManager = pmComponent;\n  }\n\n  /*\n  ---------------------------------------\n  ------- React lifecycle methods -------\n  ---------------------------------------\n  */\n\n  /**\n   * Logic performed before the mounting of the component.\n   */\n  componentWillMount(): void {\n    this.clearCache();\n    this.createGlobalEditorPortal();\n  }\n\n  /**\n   * Initialize Handsontable after the component has mounted.\n   */\n  componentDidMount(): void {\n    const hotTableComponent = this;\n    const newGlobalSettings = this.createNewGlobalSettings();\n\n    this.hotInstance = new Handsontable.Core(this.hotElementRef, newGlobalSettings);\n\n    this.hotInstance.addHook('beforeRender', function (isForced) {\n      hotTableComponent.handsontableBeforeRender();\n    });\n\n    this.hotInstance.addHook('afterRender', function () {\n      hotTableComponent.handsontableAfterRender();\n    });\n\n    // `init` missing in Handsontable's type definitions.\n    (this.hotInstance as any).init();\n\n    this.displayAutoSizeWarning(newGlobalSettings);\n  }\n\n  /**\n   * Logic performed before the component update.\n   */\n  componentWillUpdate(nextProps: Readonly<HotTableProps>, nextState: Readonly<{}>, nextContext: any): void {\n    this.clearCache();\n    removeEditorContainers(this.getOwnerDocument());\n    this.createGlobalEditorPortal(nextProps.children);\n  }\n\n  /**\n   * Logic performed after the component update.\n   */\n  componentDidUpdate(): void {\n    const newGlobalSettings = this.createNewGlobalSettings();\n    this.updateHot(newGlobalSettings);\n\n    this.displayAutoSizeWarning(newGlobalSettings);\n  }\n\n  /**\n   * Destroy the Handsontable instance when the parent component unmounts.\n   */\n  componentWillUnmount(): void {\n    this.hotInstance.destroy();\n    removeEditorContainers(this.getOwnerDocument());\n  }\n\n  /**\n   * Render the component.\n   */\n  render(): React.ReactElement {\n    const {id, className, style} = getContainerAttributesProps(this.props);\n    const isHotColumn = (childNode: any) => childNode.type === HotColumn;\n    let children = React.Children.toArray(this.props.children);\n\n    // filter out anything that's not a HotColumn\n    children = children.filter(function (childNode: any) {\n      return isHotColumn(childNode);\n    });\n\n    // clone the HotColumn nodes and extend them with the callbacks\n    let childClones = children.map((childNode: React.ReactElement, columnIndex: number) => {\n      return React.cloneElement(childNode, {\n        _componentRendererColumns: this.componentRendererColumns,\n        _emitColumnSettings: this.setHotColumnSettings.bind(this),\n        _columnIndex: columnIndex,\n        _getChildElementByType: getChildElementByType.bind(this),\n        _getRendererWrapper: this.getRendererWrapper.bind(this),\n        _getEditorClass: this.getEditorClass.bind(this),\n        _getOwnerDocument: this.getOwnerDocument.bind(this),\n        _getEditorCache: this.getEditorCache.bind(this),\n        children: childNode.props.children\n      } as object);\n    });\n\n    // add the global editor to the list of children\n    childClones.push(this.getGlobalEditorPortal());\n\n    return (\n      <React.Fragment>\n        <div ref={this.setHotElementRef.bind(this)} id={id} className={className} style={style}>\n          {childClones}\n        </div>\n        <PortalManager ref={this.setPortalManagerRef.bind(this)}></PortalManager>\n      </React.Fragment>\n    )\n  }\n}\n\nexport default HotTable;\nexport { HotTable };\n"
  },
  {
    "path": "src/index.tsx",
    "content": "export * from './hotColumn';\nexport * from './hotTable';\nexport * from './types';\nexport * from './baseEditorComponent';\nexport { default } from './hotTable';\n"
  },
  {
    "path": "src/json.d.ts",
    "content": "declare module \"*.json\" {\n  const value: any;\n  export default value;\n}\n\ndeclare module \"json!*\" {\n  const value: any;\n  export default value;\n}\n"
  },
  {
    "path": "src/portalManager.tsx",
    "content": "import React from 'react';\n\n/**\n * Component class used to manage the renderer component portals.\n */\nexport class PortalManager extends React.Component<{}, {portals?: React.ReactPortal[]}> {\n  constructor(props) {\n    super(props);\n\n    this.state = {\n      portals: []\n    };\n  }\n\n  render(): React.ReactNode {\n    return (\n      <React.Fragment>\n        {this.state.portals}\n      </React.Fragment>\n    )\n  }\n}\n"
  },
  {
    "path": "src/settingsMapper.ts",
    "content": "import Handsontable from 'handsontable';\nimport { HotTableProps } from './types';\n\nexport class SettingsMapper {\n  /**\n   * Parse component settings into Handosntable-compatible settings.\n   *\n   * @param {Object} properties Object containing properties from the HotTable object.\n   * @returns {Object} Handsontable-compatible settings object.\n   */\n  static getSettings(properties: HotTableProps): Handsontable.GridSettings {\n    let newSettings: Handsontable.GridSettings = {};\n\n    if (properties.settings) {\n      let settings = properties.settings;\n      for (const key in settings) {\n        if (settings.hasOwnProperty(key)) {\n          newSettings[key] = settings[key];\n        }\n      }\n    }\n\n    for (const key in properties) {\n      if (key !== 'settings' && key !== 'children' && properties.hasOwnProperty(key)) {\n        newSettings[key] = properties[key];\n      }\n    }\n\n    return newSettings;\n  }\n}\n"
  },
  {
    "path": "src/types.tsx",
    "content": "import Handsontable from 'handsontable';\nimport React from 'react';\nimport { ConnectedComponent } from 'react-redux';\n\n/**\n * Type of the editor component's ReactElement.\n */\nexport type HotEditorElement = React.ReactElement<{}, ConnectedComponent<React.FunctionComponent, any> | any>;\n\n/**\n * Interface for the `prop` of the HotTable component - extending the default Handsontable settings with additional,\n * component-related properties.\n */\nexport interface HotTableProps extends Handsontable.GridSettings {\n  id?: string,\n  className?: string,\n  style?: React.CSSProperties,\n  settings?: Handsontable.GridSettings\n  children?: React.ReactNode\n}\n\n/**\n * Interface for the props of the component-based editors.\n */\nexport interface HotEditorProps {\n  \"hot-editor\": any,\n  id?: string,\n  className?: string,\n  style?: React.CSSProperties,\n}\n\n/**\n * Properties related to the HotColumn architecture.\n */\nexport interface HotColumnProps extends Handsontable.GridSettings {\n  _componentRendererColumns?: Map<number | string, boolean>;\n  _emitColumnSettings?: (columnSettings: Handsontable.GridSettings, columnIndex: number) => void;\n  _columnIndex?: number,\n  _getChildElementByType?: (children: React.ReactNode, type: string) => React.ReactElement;\n  _getRendererWrapper?: (rendererNode: React.ReactElement) => Handsontable.renderers.Base;\n  _getEditorClass?: (editorElement: React.ReactElement) => typeof Handsontable.editors.BaseEditor;\n  _getEditorCache?: () => Map<Function, React.Component>;\n  _getOwnerDocument?: () => Document;\n  children?: React.ReactNode;\n}\n"
  },
  {
    "path": "test/_helpers.tsx",
    "content": "import React from 'react';\nimport { HotTable } from '../src/hotTable';\nimport { addUnsafePrefixes } from '../src/helpers';\nimport { BaseEditorComponent } from '../src/baseEditorComponent';\n\nexport function sleep(delay = 100) {\n  return Promise.resolve({\n    then(resolve) {\n      if (delay === 0) {\n        setImmediate(resolve);\n      } else {\n        setTimeout(resolve, delay);\n      }\n    }\n  });\n}\n\nexport function mockElementDimensions(element, width, height) {\n  Object.defineProperty(element, 'clientWidth', {\n    value: width\n  });\n  Object.defineProperty(element, 'clientHeight', {\n    value: height\n  });\n\n  Object.defineProperty(element, 'offsetWidth', {\n    value: width\n  });\n  Object.defineProperty(element, 'offsetHeight', {\n    value: height\n  });\n}\n\nexport function simulateKeyboardEvent(type, keyCode) {\n  const event = document.createEvent('KeyboardEvent');\n  const init = (event as any).initKeyboardEvent !== void 0 ? 'initKeyboardEvent' : 'initKeyEvent';\n\n  event[init](type, true, true, window, false, false, false, false, keyCode, 0);\n\n  document.activeElement.dispatchEvent(event);\n}\n\nexport function simulateMouseEvent(element, type) {\n  const event = document.createEvent('Events');\n  event.initEvent(type, true, false);\n\n  element.dispatchEvent(event);\n}\n\nclass IndividualPropsWrapper extends React.Component<{ref?: string, id?: string}, {hotSettings?: object}> {\n  hotTable: typeof HotTable;\n\n  constructor(props) {\n    super(props);\n\n    addUnsafePrefixes(this);\n  }\n\n  componentWillMount() {\n    this.setState({});\n  }\n\n  private setHotElementRef(component: typeof HotTable): void {\n    this.hotTable = component;\n  }\n\n  render(): React.ReactElement {\n    return (\n      <div>\n        <HotTable\n          licenseKey=\"non-commercial-and-evaluation\"\n          ref={this.setHotElementRef.bind(this)}\n          id=\"hot\" {...this.state.hotSettings}\n          autoRowSize={false}\n          autoColumnSize={false}\n        />\n      </div>\n    );\n  }\n}\n\nexport { IndividualPropsWrapper };\n\nclass SingleObjectWrapper extends React.Component<{ref?: string, id?: string}, {hotSettings?: object}> {\n  hotTable: typeof HotTable;\n\n  constructor(props) {\n    super(props);\n\n    addUnsafePrefixes(this);\n  }\n\n  private setHotElementRef(component: typeof HotTable): void {\n    this.hotTable = component;\n  }\n\n  componentWillMount() {\n    this.setState({});\n  }\n\n  render(): React.ReactElement {\n    return (\n      <div>\n        <HotTable\n          licenseKey=\"non-commercial-and-evaluation\"\n          ref={this.setHotElementRef.bind(this)}\n          id=\"hot\"\n          settings={this.state.hotSettings}\n          autoRowSize={false}\n          autoColumnSize={false}\n        />\n      </div>\n    );\n  }\n}\n\nexport { SingleObjectWrapper };\n\nexport class RendererComponent extends React.Component<any, any> {\n  render(): React.ReactElement<string> {\n    return (\n      <>\n        value: {this.props.value}\n      </>\n    );\n  }\n}\n\nexport class EditorComponent extends BaseEditorComponent<{}, {value?: any}> {\n  mainElementRef: any;\n  containerStyle: any;\n\n  constructor(props) {\n    super(props);\n\n    this.mainElementRef = React.createRef();\n\n    this.state = {\n      value: ''\n    };\n\n    this.containerStyle = {\n      display: 'none'\n    };\n  }\n\n  getValue() {\n    return this.state.value;\n  }\n\n  setValue(value, callback) {\n    this.setState((state, props) => {\n      return {value: value};\n    }, callback);\n  }\n\n  setNewValue() {\n    this.setValue('new-value', () => {\n      this.finishEditing();\n    })\n  }\n\n  open() {\n    this.mainElementRef.current.style.display = 'block';\n  }\n\n  close() {\n    this.mainElementRef.current.style.display = 'none';\n  }\n\n  render(): React.ReactElement<string> {\n    return (\n      <div style={this.containerStyle} ref={this.mainElementRef} id=\"editorComponentContainer\">\n        <button onClick={this.setNewValue.bind(this)}></button>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/autoSizeWarning.spec.tsx",
    "content": "import React from 'react';\nimport {\n  mount,\n  ReactWrapper\n} from 'enzyme';\nimport {\n  HotTable\n} from '../src/hotTable';\nimport {\n  HotColumn\n} from '../src/hotColumn';\nimport {\n  mockElementDimensions,\n  sleep\n} from './_helpers';\nimport {\n  AUTOSIZE_WARNING\n} from '../src/helpers';\nimport Handsontable from 'handsontable';\n\nbeforeEach(() => {\n  let container = document.createElement('DIV');\n  container.id = 'hotContainer';\n  document.body.appendChild(container);\n});\n\ndescribe('`autoRowSize`/`autoColumns` warning', () => {\n  it('should recognize whether `autoRowSize` or `autoColumnSize` is enabled and throw a warning, if a global component-based renderer' +\n    'is defined (using the default Handsontable settings - autoColumnSize is enabled by default)', async (done) => {\n    console.warn = jasmine.createSpy('warn');\n\n    const RendererComponent = function (props) {\n      return <>test</>\n    };\n\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                id=\"test-hot\"\n                data={Handsontable.helper.createSpreadsheetData(3, 2)}\n                width={300}\n                height={300}\n                init={function () {\n                  mockElementDimensions(this.rootElement, 300, 300);\n                }}>\n        <RendererComponent hot-renderer></RendererComponent>\n      </HotTable>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    expect(console.warn).toHaveBeenCalledWith(AUTOSIZE_WARNING);\n\n    wrapper.detach();\n    done();\n  });\n\n  it('should recognize whether `autoRowSize` or `autoColumnSize` is enabled and throw a warning, if a global component-based renderer' +\n    'is defined', async (done) => {\n    console.warn = jasmine.createSpy('warn');\n\n    const RendererComponent = function (props) {\n      return <>test</>\n    };\n\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                id=\"test-hot\"\n                data={Handsontable.helper.createSpreadsheetData(3, 2)}\n                width={300}\n                height={300}\n                autoRowSize={false}\n                autoColumnSize={true}\n                init={function () {\n                  mockElementDimensions(this.rootElement, 300, 300);\n                }}>\n        <RendererComponent hot-renderer></RendererComponent>\n      </HotTable>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    expect(console.warn).toHaveBeenCalledWith(AUTOSIZE_WARNING);\n\n    wrapper.detach();\n    done();\n  });\n\n  it('should recognize whether `autoRowSize` or `autoColumnSize` is enabled and throw a warning, if a component-based renderer' +\n    'is defined for any column (using the default Handsontable settings - autoColumnSize enabled by default)', async (done) => {\n    console.warn = jasmine.createSpy('warn');\n\n    const RendererComponent = function (props) {\n      return <>test</>\n    };\n\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                id=\"test-hot\"\n                data={Handsontable.helper.createSpreadsheetData(3, 3)}\n                width={300}\n                height={300}\n                init={function () {\n                  mockElementDimensions(this.rootElement, 300, 300);\n                }}>\n        <HotColumn/>\n        <HotColumn>\n          <RendererComponent hot-renderer></RendererComponent>\n        </HotColumn>\n        <HotColumn/>\n      </HotTable>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    expect(console.warn).toHaveBeenCalledWith(AUTOSIZE_WARNING);\n\n    wrapper.detach();\n    done();\n  });\n\n  it('should recognize whether `autoRowSize` or `autoColumnSize` is enabled and throw a warning, if a component-based renderer' +\n    'is defined for any column', async (done) => {\n    console.warn = jasmine.createSpy('warn');\n\n    const RendererComponent = function (props) {\n      return <>test</>\n    };\n\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                id=\"test-hot\"\n                data={Handsontable.helper.createSpreadsheetData(3, 3)}\n                width={300}\n                height={300}\n                autoColumnSize={false}\n                autoRowSize={true}\n                init={function () {\n                  mockElementDimensions(this.rootElement, 300, 300);\n                }}>\n        <HotColumn/>\n        <HotColumn>\n          <RendererComponent hot-renderer></RendererComponent>\n        </HotColumn>\n        <HotColumn/>\n      </HotTable>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    expect(console.warn).toHaveBeenCalledWith(AUTOSIZE_WARNING);\n\n    wrapper.detach();\n    done();\n  });\n\n  it('should throw a warning, when `autoRowSize` or `autoColumnSize` is defined, and both function-based and component-based renderers are defined', async (done) => {\n    console.warn = jasmine.createSpy('warn');\n\n    const RendererComponent = function (props) {\n      return <>test</>\n    };\n\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                id=\"test-hot\"\n                data={Handsontable.helper.createSpreadsheetData(3, 3)}\n                width={300}\n                height={300}\n                autoRowSize={false}\n                autoColumnSize={true}\n                columns={function(columnIndex) {\n                  return {\n                    renderer: function() {}\n                  }\n                }}\n                init={function () {\n                  mockElementDimensions(this.rootElement, 300, 300);\n                }}>\n        <HotColumn/>\n        <HotColumn>\n          <RendererComponent hot-renderer/>\n        </HotColumn>\n        <HotColumn/>\n      </HotTable>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    expect(console.warn).toHaveBeenCalledWith(AUTOSIZE_WARNING);\n\n    wrapper.detach();\n    done();\n  });\n\n  it('should NOT throw any warnings, when `autoRowSize` or `autoColumnSize` is defined, but only global function-based renderers were defined', async (done) => {\n    console.warn = jasmine.createSpy('warn');\n\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                id=\"test-hot\"\n                data={Handsontable.helper.createSpreadsheetData(3, 3)}\n                width={300}\n                height={300}\n                autoRowSize={true}\n                autoColumnSize={false}\n                renderer={function() {}}\n                init={function () {\n                  mockElementDimensions(this.rootElement, 300, 300);\n                }}>\n        <HotColumn/>\n        <HotColumn/>\n        <HotColumn/>\n      </HotTable>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    expect(console.warn).not.toHaveBeenCalled();\n\n    wrapper.detach();\n    done();\n  });\n\n  it('should NOT throw any warnings, when `autoRowSize` or `autoColumnSize` is defined, but only function-based renderers were defined for columns', async (done) => {\n    console.warn = jasmine.createSpy('warn');\n\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                id=\"test-hot\"\n                data={Handsontable.helper.createSpreadsheetData(3, 3)}\n                width={300}\n                height={300}\n                autoRowSize={true}\n                autoColumnSize={true}\n                columns={[{renderer: function() {}}]}\n                init={function () {\n                  mockElementDimensions(this.rootElement, 300, 300);\n                }}>\n        <HotColumn/>\n        <HotColumn/>\n        <HotColumn/>\n      </HotTable>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    expect(console.warn).not.toHaveBeenCalled();\n\n    wrapper.detach();\n    done();\n  });\n\n  it('should NOT throw any warnings, when `autoRowSize` or `autoColumnSize` is defined, but only function-based renderers were defined for columns, when ' +\n    'the `columns` option is defined as a function', async (done) => {\n    console.warn = jasmine.createSpy('warn');\n\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                id=\"test-hot\"\n                data={Handsontable.helper.createSpreadsheetData(3, 3)}\n                width={300}\n                height={300}\n                autoRowSize={false}\n                autoColumnSize={true}\n                columns={function(columnIndex) {\n                  return {\n                    renderer: function() {}\n                  }\n                }}\n                init={function () {\n                  mockElementDimensions(this.rootElement, 300, 300);\n                }}>\n        <HotColumn/>\n        <HotColumn/>\n        <HotColumn/>\n      </HotTable>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    expect(console.warn).not.toHaveBeenCalled();\n\n    wrapper.detach();\n    done();\n  });\n});\n"
  },
  {
    "path": "test/componentInternals.spec.tsx",
    "content": "import React from 'react';\nimport {\n  mount,\n  ReactWrapper\n} from 'enzyme';\nimport {\n  HotTable\n} from '../src/hotTable';\nimport {\n  HotColumn\n} from '../src/hotColumn';\nimport {\n  mockElementDimensions,\n  sleep,\n  RendererComponent,\n  EditorComponent\n} from './_helpers';\nimport { BaseEditorComponent } from '../src/baseEditorComponent';\nimport Handsontable from 'handsontable';\n\nbeforeEach(() => {\n  let container = document.createElement('DIV');\n  container.id = 'hotContainer';\n  document.body.appendChild(container);\n});\n\ndescribe('Subcomponent state', () => {\n  it('should be possible to set the state of the renderer components passed to HotTable and HotColumn', async (done) => {\n    class RendererComponent2 extends React.Component<any, any, any> {\n      constructor(props) {\n        super(props);\n\n        this.state = {\n          value: 'initial'\n        }\n      }\n\n      render(): React.ReactElement<string> {\n        return (\n          <>\n            {this.state.value}\n          </>\n        );\n      }\n    }\n\n    let zeroRendererInstance = null;\n    let oneRendererInstance = null;\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                id=\"test-hot\"\n                data={Handsontable.helper.createSpreadsheetData(3, 2)}\n                width={300}\n                height={300}\n                rowHeights={23}\n                colWidths={50}\n                autoRowSize={false}\n                autoColumnSize={false}\n                init={function () {\n                  mockElementDimensions(this.rootElement, 300, 300);\n                }}>\n        <RendererComponent2 ref={function (instance) {\n          if (instance && instance.props.row === 0 && instance.props.col === 0) {\n            zeroRendererInstance = instance;\n          }\n        }} hot-renderer></RendererComponent2>\n        <HotColumn/>\n        <HotColumn>\n          <RendererComponent2 ref={function (instance) {\n            if (instance && instance.props.row === 0 && instance.props.col === 1) {\n              oneRendererInstance = instance;\n            }\n          }} hot-renderer></RendererComponent2>\n        </HotColumn>\n      </HotTable>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    const hotTableInstance = wrapper.instance();\n    const hotInstance = hotTableInstance.hotInstance;\n\n    expect(hotInstance.getCell(0, 0).innerHTML).toEqual('<div>initial</div>');\n    expect(hotInstance.getCell(0, 1).innerHTML).toEqual('<div>initial</div>');\n\n    zeroRendererInstance.setState({\n      value: 'altered'\n    });\n\n    oneRendererInstance.setState({\n      value: 'altered as well'\n    });\n\n    expect(hotInstance.getCell(0, 0).innerHTML).toEqual('<div>altered</div>');\n    expect(hotInstance.getCell(0, 1).innerHTML).toEqual('<div>altered as well</div>');\n\n    wrapper.detach();\n    done();\n  });\n\n  it('should be possible to set the state of the editor components passed to HotTable and HotColumn', async (done) => {\n    class RendererEditor2 extends BaseEditorComponent {\n      constructor(props) {\n        super(props);\n\n        this.state = {\n          value: 'initial'\n        }\n      }\n\n      render(): React.ReactElement<string> {\n        return (\n          <div id={this.props.editorId}>\n            {this.state.value}\n          </div>\n        );\n      }\n    }\n\n    let globalEditorInstance = null;\n    let columnEditorInstance = null;\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                id=\"test-hot\"\n                data={Handsontable.helper.createSpreadsheetData(3, 2)}\n                width={300}\n                height={300}\n                rowHeights={23}\n                colWidths={50}\n                init={function () {\n                  mockElementDimensions(this.rootElement, 300, 300);\n                }}>\n        <RendererEditor2 editorId={'first-editor'} ref={function (instance) {\n          globalEditorInstance = instance;\n        }} hot-editor></RendererEditor2>\n        <HotColumn/>\n        <HotColumn>\n          <RendererEditor2 editorId={'second-editor'} ref={function (instance) {\n            columnEditorInstance = instance;\n          }} hot-editor></RendererEditor2>\n        </HotColumn>\n      </HotTable>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    const hotTableInstance = wrapper.instance();\n    const hotInstance = hotTableInstance.hotInstance;\n\n    expect(document.querySelector('#first-editor').innerHTML).toEqual('initial');\n    expect(document.querySelector('#second-editor').innerHTML).toEqual('initial');\n\n    globalEditorInstance.setState({\n      value: 'altered'\n    });\n\n    columnEditorInstance.setState({\n      value: 'altered as well'\n    });\n\n    expect(document.querySelector('#first-editor').innerHTML).toEqual('altered');\n    expect(document.querySelector('#second-editor').innerHTML).toEqual('altered as well');\n\n    wrapper.detach();\n    done();\n  });\n});\n\ndescribe('Component lifecyle', () => {\n  it('renderer components should trigger their lifecycle methods', async (done) => {\n    class RendererComponent2 extends React.Component<any, any, any> {\n      constructor(props) {\n        super(props);\n\n        rendererCounters.set(`${this.props.row}-${this.props.col}`, {\n          willMount: 0,\n          didMount: 0,\n          willUnmount: 0\n        });\n      }\n\n      UNSAFE_componentWillMount(): void {\n        const counters = rendererCounters.get(`${this.props.row}-${this.props.col}`);\n        counters.willMount++;\n      }\n\n      componentDidMount(): void {\n        const counters = rendererCounters.get(`${this.props.row}-${this.props.col}`);\n        counters.didMount++;\n      }\n\n      componentWillUnmount(): void {\n        const counters = rendererCounters.get(`${this.props.row}-${this.props.col}`);\n        counters.willUnmount++;\n      }\n\n      render(): React.ReactElement<string> {\n        return (\n          <>\n            test\n          </>\n        );\n      }\n    }\n\n    let secondGo = false;\n    const rendererRefs = new Map();\n    const rendererCounters = new Map();\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                id=\"test-hot\"\n                data={Handsontable.helper.createSpreadsheetData(3, 2)}\n                width={300}\n                height={300}\n                rowHeights={23}\n                colWidths={50}\n                autoRowSize={false}\n                autoColumnSize={false}\n                init={function () {\n                  mockElementDimensions(this.rootElement, 300, 300);\n                }}>\n        <RendererComponent2 ref={function (instance) {\n          if (!secondGo && instance) {\n            rendererRefs.set(`${instance.props.row}-${instance.props.col}`, instance);\n          }\n        }} hot-renderer></RendererComponent2>\n        <HotColumn/>\n        <HotColumn>\n          <RendererComponent2 ref={function (instance) {\n            if (!secondGo && instance) {\n              rendererRefs.set(`${instance.props.row}-${instance.props.col}`, instance);\n            }\n          }} hot-renderer></RendererComponent2>\n        </HotColumn>\n      </HotTable>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    const hotTableInstance = wrapper.instance();\n    const hotInstance = hotTableInstance.hotInstance;\n\n    rendererCounters.forEach((counters) => {\n      expect(counters.willMount).toEqual(1);\n      expect(counters.didMount).toEqual(1);\n      expect(counters.willUnmount).toEqual(0);\n    });\n\n    secondGo = true;\n\n    hotInstance.render();\n    await sleep(300);\n\n    rendererCounters.forEach((counters) => {\n      expect(counters.willMount).toEqual(1);\n      expect(counters.didMount).toEqual(1);\n      expect(counters.willUnmount).toEqual(1);\n    });\n\n    wrapper.detach();\n    done();\n  });\n\n  it('editor components should trigger their lifecycle methods', async (done) => {\n    class EditorComponent2 extends BaseEditorComponent {\n      constructor(props) {\n        super(props);\n\n        editorCounters.set(`${this.props.row}-${this.props.col}`, {\n          willMount: 0,\n          didMount: 0,\n          willUnmount: 0\n        });\n      }\n\n      UNSAFE_componentWillMount(): void {\n        const counters = editorCounters.get(`${this.props.row}-${this.props.col}`);\n        counters.willMount++;\n      }\n\n      componentDidMount(): void {\n        const counters = editorCounters.get(`${this.props.row}-${this.props.col}`);\n        counters.didMount++;\n      }\n\n      componentWillUnmount(): void {\n        const counters = editorCounters.get(`${this.props.row}-${this.props.col}`);\n        counters.willUnmount++;\n      }\n\n      render(): React.ReactElement<string> {\n        return (\n          <>\n            test\n          </>\n        );\n      }\n    }\n\n    let secondGo = false;\n    const editorRefs = new Map();\n    const editorCounters = new Map();\n    const childrenArray = [\n      <EditorComponent2 ref={function (instance) {\n        if (!secondGo && instance) {\n          editorRefs.set(`EditorComponent2`, instance);\n        }\n      }} hot-editor key={Math.random()}></EditorComponent2>\n    ];\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                id=\"test-hot\"\n                data={Handsontable.helper.createSpreadsheetData(3, 2)}\n                width={300}\n                height={300}\n                rowHeights={23}\n                colWidths={50}\n                init={function () {\n                  mockElementDimensions(this.rootElement, 300, 300);\n                }}>\n        {childrenArray}\n      </HotTable>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    const hotTableInstance = wrapper.instance();\n\n    editorCounters.forEach((counters) => {\n      expect(counters.willMount).toEqual(1);\n      expect(counters.didMount).toEqual(1);\n      expect(counters.willUnmount).toEqual(0);\n    });\n\n    secondGo = true;\n\n    childrenArray.length = 0;\n    hotTableInstance.forceUpdate();\n    await sleep(100);\n\n    editorCounters.forEach((counters) => {\n      expect(counters.willMount).toEqual(1);\n      expect(counters.didMount).toEqual(1);\n      expect(counters.willUnmount).toEqual(1);\n    });\n\n    wrapper.detach();\n    done();\n  });\n});\n"
  },
  {
    "path": "test/hotColumn.spec.tsx",
    "content": "import React from 'react';\nimport {\n  mount,\n  ReactWrapper\n} from 'enzyme';\nimport Handsontable from 'handsontable';\nimport { HotTable } from '../src/hotTable';\nimport { HotColumn } from '../src/hotColumn';\nimport {\n  RendererComponent,\n  mockElementDimensions,\n  sleep,\n  EditorComponent,\n  simulateKeyboardEvent,\n  simulateMouseEvent\n} from './_helpers';\n\nbeforeEach(() => {\n  let container = document.createElement('DIV');\n  container.id = 'hotContainer';\n  document.body.appendChild(container);\n});\n\ndescribe('Passing column settings using HotColumn', () => {\n  it('should apply the Handsontable settings passed as HotColumn arguments to the Handsontable instance', async (done) => {\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <HotTable\n        licenseKey=\"non-commercial-and-evaluation\"\n        id=\"test-hot\" data={[[2]]}\n        readOnly={false}\n      >\n        <HotColumn title=\"test title\"></HotColumn>\n        <HotColumn readOnly={true}></HotColumn>\n      </HotTable>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(300);\n\n    let hotInstance = wrapper.instance().hotInstance;\n\n    expect(hotInstance.getSettings().columns[0].title).toEqual('test title');\n    expect(hotInstance.getCellMeta(0, 0).readOnly).toEqual(false);\n\n    expect(hotInstance.getSettings().columns[1].title).toEqual(void 0);\n    expect(hotInstance.getCellMeta(0, 1).readOnly).toEqual(true);\n\n    expect(hotInstance.getSettings().licenseKey).toEqual('non-commercial-and-evaluation');\n\n    wrapper.detach();\n\n    done();\n  });\n});\n\ndescribe('Renderer configuration using React components', () => {\n  it('should use the renderer component as Handsontable renderer, when it\\'s nested under HotColumn and assigned the \\'hot-renderer\\' attribute', async (done) => {\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                id=\"test-hot\"\n                data={Handsontable.helper.createSpreadsheetData(100, 2)}\n                width={300}\n                height={300}\n                rowHeights={23}\n                colWidths={50}\n                autoRowSize={false}\n                autoColumnSize={false}\n                init={function () {\n                  mockElementDimensions(this.rootElement, 300, 300);\n                }}>\n        <HotColumn/>\n        <HotColumn>\n          <RendererComponent hot-renderer></RendererComponent>\n        </HotColumn>\n      </HotTable>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(300);\n\n    let hotInstance = wrapper.instance().hotInstance;\n\n    expect(hotInstance.getCell(0, 0).innerHTML).toEqual('A1');\n    expect(hotInstance.getCell(0, 1).innerHTML).toEqual('<div>value: B1</div>');\n\n    hotInstance.scrollViewportTo(99, 0);\n    hotInstance.render();\n\n    await sleep(300);\n\n    expect(hotInstance.getCell(99, 0).innerHTML).toEqual('A100');\n    expect(hotInstance.getCell(99, 1).innerHTML).toEqual('<div>value: B100</div>');\n\n    wrapper.detach();\n\n    done();\n  });\n});\n\ndescribe('Editor configuration using React components', () => {\n  it('should use the editor component as Handsontable editor, when it\\'s nested under HotTable and assigned the \\'hot-editor\\' attribute', async (done) => {\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                id=\"test-hot\"\n                data={Handsontable.helper.createSpreadsheetData(3, 2)}\n                width={300}\n                height={300}\n                rowHeights={23}\n                colWidths={50}\n                init={function () {\n                  mockElementDimensions(this.rootElement, 300, 300);\n                }}>\n        <HotColumn/>\n        <HotColumn>\n          <EditorComponent hot-editor></EditorComponent>\n        </HotColumn>\n      </HotTable>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    const hotInstance = wrapper.instance().hotInstance;\n\n    expect((document.querySelector('#editorComponentContainer') as any).style.display).toEqual('none');\n\n    hotInstance.selectCell(0, 1);\n    simulateKeyboardEvent('keydown', 13);\n\n    expect((document.querySelector('#editorComponentContainer') as any).style.display).toEqual('block');\n\n    expect(hotInstance.getDataAtCell(0, 1)).toEqual('B1');\n\n    simulateMouseEvent(document.querySelector('#editorComponentContainer button'), 'click');\n\n    expect(hotInstance.getDataAtCell(0, 1)).toEqual('new-value');\n\n    hotInstance.getActiveEditor().close();\n\n    expect((document.querySelector('#editorComponentContainer') as any).style.display).toEqual('none');\n\n    hotInstance.selectCell(0, 0);\n    simulateKeyboardEvent('keydown', 13);\n\n    expect((document.querySelector('#editorComponentContainer') as any).style.display).toEqual('none');\n\n    wrapper.detach();\n\n    done();\n  });\n});\n\ndescribe('Dynamic HotColumn configuration changes', () => {\n  it('should be possible to rearrange and change the column + editor + renderer configuration dynamically', async (done) => {\n    function RendererComponent2(props) {\n      return (\n        <>r2: {props.value}</>\n      );\n    }\n\n    class WrapperComponent extends React.Component<any, any> {\n      constructor(props) {\n        super(props);\n\n        this.state = {\n          setup: [\n            <RendererComponent hot-renderer key={'1'}/>,\n            <HotColumn title=\"test title\" className=\"first-column-class-name\" key={'2'}>\n              <EditorComponent className=\"editor-className-1\" id=\"editor-id-1\" style={{background: 'red'}} hot-editor/>\n            </HotColumn>,\n            <HotColumn title=\"test title 2\" key={'3'}>\n              <RendererComponent2 hot-renderer></RendererComponent2>\n            </HotColumn>\n          ]\n        }\n      }\n\n      render() {\n        return (\n          <HotTable licenseKey=\"non-commercial-and-evaluation\" id=\"test-hot\"\n                    data={Handsontable.helper.createSpreadsheetData(3, 2)}\n                    width={300}\n                    height={300}\n                    rowHeights={23}\n                    colWidths={50}\n                    readOnly={false}\n                    autoRowSize={false}\n                    autoColumnSize={false}\n                    init={function () {\n                      mockElementDimensions(this.rootElement, 300, 300);\n                    }}\n                    ref={hotTableInstanceRef}>\n            {this.state.setup}\n          </HotTable>\n        );\n      };\n    }\n\n    let hotTableInstanceRef = React.createRef();\n\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <WrapperComponent/>\n      , {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(300);\n\n    let hotInstance = (hotTableInstanceRef.current as any).hotInstance;\n    let editorElement = document.querySelector('#editorComponentContainer');\n\n    expect(hotInstance.getSettings().columns[0].title).toEqual('test title');\n    expect(hotInstance.getSettings().columns[0].className).toEqual('first-column-class-name');\n    expect(hotInstance.getCell(0, 0).innerHTML).toEqual('<div>value: A1</div>');\n    expect(hotInstance.getCell(1, 0).innerHTML).toEqual('<div>value: A2</div>');\n    hotInstance.selectCell(0, 0);\n    hotInstance.getActiveEditor().open();\n    expect(hotInstance.getActiveEditor().constructor.name).toEqual('CustomEditor');\n    expect(hotInstance.getActiveEditor().editorComponent.__proto__.constructor.name).toEqual('EditorComponent');\n    expect(editorElement.style.display).toEqual('block');\n    expect(editorElement.parentNode.style.background).toEqual('red');\n    expect(editorElement.parentNode.id).toEqual('editor-id-1');\n    expect(editorElement.parentNode.className.includes('editor-className-1')).toBe(true);\n\n    hotInstance.getActiveEditor().close();\n\n    expect(hotInstance.getSettings().columns[1].title).toEqual('test title 2');\n    expect(hotInstance.getSettings().columns[1].className).toEqual(void 0);\n    expect(hotInstance.getCell(0, 1).innerHTML).toEqual('<div>r2: B1</div>');\n    expect(hotInstance.getCell(1, 1).innerHTML).toEqual('<div>r2: B2</div>');\n    hotInstance.selectCell(0, 1);\n    expect(hotInstance.getActiveEditor().constructor.name).toEqual('TextEditor');\n    expect(hotInstance.getActiveEditor().editorComponent).toEqual(void 0);\n    expect((document.querySelector('#editorComponentContainer') as any).style.display).toEqual('none');\n\n    wrapper.instance().setState({\n      setup: [\n        <EditorComponent className=\"editor-className-2\" id=\"editor-id-2\" style={{background: 'blue'}} hot-editor key={'1'}/>,\n        <HotColumn title=\"test title 2\" key={'2'}>\n          <RendererComponent2 hot-renderer></RendererComponent2>\n        </HotColumn>,\n        <HotColumn title=\"test title\" className=\"first-column-class-name\" key={'3'}>\n          <RendererComponent hot-renderer/>\n        </HotColumn>\n      ]\n    });\n\n    await sleep(100);\n\n    editorElement = document.querySelector('#editorComponentContainer');\n\n    expect(hotInstance.getSettings().columns[0].title).toEqual('test title 2');\n    expect(hotInstance.getSettings().columns[0].className).toEqual(void 0);\n    expect(hotInstance.getCell(0, 0).innerHTML).toEqual('<div>r2: A1</div>');\n    expect(hotInstance.getCell(1, 0).innerHTML).toEqual('<div>r2: A2</div>');\n    hotInstance.selectCell(0, 0);\n    hotInstance.getActiveEditor().open();\n    expect(hotInstance.getActiveEditor().constructor.name).toEqual('CustomEditor');\n    expect(hotInstance.getActiveEditor().editorComponent.__proto__.constructor.name).toEqual('EditorComponent');\n    expect(editorElement.style.display).toEqual('block');\n    expect(editorElement.parentNode.style.background).toEqual('blue');\n    expect(editorElement.parentNode.id).toEqual('editor-id-2');\n    expect(editorElement.parentNode.className.includes('editor-className-2')).toBe(true);\n    hotInstance.getActiveEditor().close();\n\n    expect(hotInstance.getSettings().columns[1].title).toEqual('test title');\n    expect(hotInstance.getSettings().columns[1].className).toEqual('first-column-class-name');\n    expect(hotInstance.getCell(0, 1).innerHTML).toEqual('<div>value: B1</div>');\n    expect(hotInstance.getCell(1, 1).innerHTML).toEqual('<div>value: B2</div>');\n    hotInstance.selectCell(0, 1);\n    hotInstance.getActiveEditor().open();\n    expect(hotInstance.getActiveEditor().constructor.name).toEqual('CustomEditor');\n    expect(hotInstance.getActiveEditor().editorComponent.__proto__.constructor.name).toEqual('EditorComponent');\n    expect((document.querySelector('#editorComponentContainer') as any).style.display).toEqual('block');\n    hotInstance.getActiveEditor().close();\n\n    expect(hotInstance.getSettings().licenseKey).toEqual('non-commercial-and-evaluation');\n\n    wrapper.detach();\n\n    done();\n  });\n});\n"
  },
  {
    "path": "test/hotTable.spec.tsx",
    "content": "import React from 'react';\nimport {\n  mount,\n  ReactWrapper\n} from 'enzyme';\nimport {\n  HotTable\n} from '../src/hotTable';\nimport {\n  IndividualPropsWrapper,\n  mockElementDimensions,\n  RendererComponent,\n  EditorComponent,\n  SingleObjectWrapper,\n  sleep,\n  simulateKeyboardEvent,\n  simulateMouseEvent\n} from './_helpers';\nimport Handsontable from 'handsontable';\n\nbeforeEach(() => {\n  let container = document.createElement('DIV');\n  container.id = 'hotContainer';\n  document.body.appendChild(container);\n});\n\ndescribe('Handsontable initialization', () => {\n  it('should render Handsontable when using the HotTable component', async (done) => {\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <HotTable\n        id=\"test-hot\"\n        data={[[2]]}\n        licenseKey=\"non-commercial-and-evaluation\"\n      />, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(300);\n\n    let hotInstance = wrapper.instance().hotInstance;\n\n    expect(hotInstance).not.toBe(null);\n    expect(hotInstance).not.toBe(void 0);\n\n    expect(hotInstance.rootElement.id).toEqual('test-hot');\n\n    wrapper.detach();\n\n    done();\n  });\n\n  it('should pass the provided properties to the Handsontable instance', async (done) => {\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <HotTable\n        id=\"test-hot\"\n        contextMenu={true}\n        rowHeaders={true}\n        colHeaders={true}\n        data={[[2]]}\n        licenseKey=\"non-commercial-and-evaluation\"/>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(300);\n    let hotInstance = wrapper.instance().hotInstance;\n\n    expect(hotInstance.getPlugin('contextMenu').enabled).toBe(true);\n    expect(hotInstance.getSettings().rowHeaders).toBe(true);\n    expect(hotInstance.getSettings().colHeaders).toBe(true);\n    expect(JSON.stringify(hotInstance.getData())).toEqual('[[2]]');\n    wrapper.detach();\n\n    done();\n  });\n});\n\ndescribe('Updating the Handsontable settings', () => {\n  it('should call the updateSettings method of Handsontable, when the component properties get updated (when providing properties individually)', async (done) => {\n    const wrapper: ReactWrapper<{}, {}, typeof IndividualPropsWrapper> = mount(\n      <IndividualPropsWrapper/>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(300);\n    const hotInstance = wrapper.instance().hotTable.hotInstance;\n\n    let updateSettingsCount = 0;\n\n    hotInstance.addHook('afterUpdateSettings', () => {\n      updateSettingsCount++;\n    });\n\n    await sleep(300);\n    wrapper.instance().setState({hotSettings: {data: [[2]], contextMenu: true, readOnly: true}});\n\n    expect(updateSettingsCount).toEqual(1);\n    wrapper.detach();\n    done();\n  });\n\n  it('should call the updateSettings method of Handsontable, when the component properties get updated (when providing properties as a single settings object)', async (done) => {\n    const wrapper: ReactWrapper<{}, {}, typeof SingleObjectWrapper> = mount(\n      <SingleObjectWrapper/>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(300);\n\n    const hotInstance = wrapper.instance().hotTable.hotInstance;\n    let updateSettingsCount = 0;\n\n    hotInstance.addHook('afterUpdateSettings', () => {\n      updateSettingsCount++;\n    });\n\n    await sleep(300);\n    wrapper.instance().setState({hotSettings: {data: [[2]], contextMenu: true, readOnly: true}});\n\n    expect(updateSettingsCount).toEqual(1);\n    wrapper.detach();\n    done();\n  });\n\n  it('should update the Handsontable options, when the component properties get updated (when providing properties individually)', async (done) => {\n    const wrapper: ReactWrapper<{}, {}, typeof IndividualPropsWrapper> = mount(\n      <IndividualPropsWrapper/>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(300);\n    const hotInstance = wrapper.instance().hotTable.hotInstance;\n\n    expect(hotInstance.getSettings().contextMenu).toEqual(void 0);\n    expect(hotInstance.getSettings().readOnly).toEqual(false);\n    expect(JSON.stringify(hotInstance.getSettings().data)).toEqual('[[null,null,null,null,null],[null,null,null,null,null],[null,null,null,null,null],[null,null,null,null,null],[null,null,null,null,null]]');\n\n    await sleep(300);\n    wrapper.instance().setState({hotSettings: {data: [[2]], contextMenu: true, readOnly: true}});\n\n    expect(hotInstance.getSettings().contextMenu).toBe(true);\n    expect(hotInstance.getSettings().readOnly).toBe(true);\n    expect(JSON.stringify(hotInstance.getSettings().data)).toEqual('[[2]]');\n    wrapper.detach();\n\n    done();\n\n  });\n\n  it('should update the Handsontable options, when the component properties get updated (when providing properties as a single settings object)', async (done) => {\n    const wrapper: ReactWrapper<{}, {}, typeof SingleObjectWrapper> = mount(\n      <SingleObjectWrapper/>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(300);\n    const hotInstance = wrapper.instance().hotTable.hotInstance;\n\n    expect(hotInstance.getSettings().contextMenu).toEqual(void 0);\n    expect(hotInstance.getSettings().readOnly).toEqual(false);\n    expect(JSON.stringify(hotInstance.getSettings().data)).toEqual('[[null,null,null,null,null],[null,null,null,null,null],[null,null,null,null,null],[null,null,null,null,null],[null,null,null,null,null]]');\n\n    await sleep(300);\n    wrapper.instance().setState({hotSettings: {data: [[2]], contextMenu: true, readOnly: true}});\n\n\n    expect(hotInstance.getSettings().contextMenu).toBe(true);\n    expect(hotInstance.getSettings().readOnly).toBe(true);\n    expect(JSON.stringify(hotInstance.getSettings().data)).toEqual('[[2]]');\n    wrapper.detach();\n\n    done();\n  });\n});\n\ndescribe('Renderer configuration using React components', () => {\n  it('should use the renderer component as Handsontable renderer, when it\\'s nested under HotTable and assigned the \\'hot-renderer\\' attribute', async (done) => {\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                id=\"test-hot\"\n                data={Handsontable.helper.createSpreadsheetData(100, 100)}\n                width={300}\n                height={300}\n                rowHeights={23}\n                colWidths={50}\n                autoRowSize={false}\n                autoColumnSize={false}\n                init={function () {\n                  mockElementDimensions(this.rootElement, 300, 300);\n                }}>\n        <RendererComponent hot-renderer></RendererComponent>\n      </HotTable>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    let hotInstance = wrapper.instance().hotInstance;\n\n    expect(hotInstance.getCell(0, 0).innerHTML).toEqual('<div>value: A1</div>');\n\n    hotInstance.scrollViewportTo(99, 0);\n    // For some reason it needs another render\n    hotInstance.render();\n    await sleep(100);\n\n    expect(hotInstance.getCell(99, 1).innerHTML).toEqual('<div>value: B100</div>');\n\n    hotInstance.scrollViewportTo(99, 99);\n    hotInstance.render();\n    await sleep(100);\n\n    expect(hotInstance.getCell(99, 99).innerHTML).toEqual('<div>value: CV100</div>');\n\n    wrapper.detach();\n\n    done();\n  });\n});\n\ndescribe('Editor configuration using React components', () => {\n  it('should use the editor component as Handsontable editor, when it\\'s nested under HotTable and assigned the \\'hot-editor\\' attribute', async (done) => {\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                id=\"test-hot\"\n                data={Handsontable.helper.createSpreadsheetData(3, 3)}\n                width={300}\n                height={300}\n                rowHeights={23}\n                colWidths={50}\n                init={function () {\n                  mockElementDimensions(this.rootElement, 300, 300);\n                }}>\n        <EditorComponent hot-editor></EditorComponent>\n      </HotTable>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    const hotInstance = wrapper.instance().hotInstance;\n\n    expect((document.querySelector('#editorComponentContainer') as any).style.display).toEqual('none');\n\n    hotInstance.selectCell(0,0);\n    simulateKeyboardEvent('keydown', 13);\n\n    expect((document.querySelector('#editorComponentContainer') as any).style.display).toEqual('block');\n\n    expect(hotInstance.getDataAtCell(0,0)).toEqual('A1');\n\n    simulateMouseEvent(document.querySelector('#editorComponentContainer button'), 'click');\n\n    expect(hotInstance.getDataAtCell(0,0)).toEqual('new-value');\n\n    hotInstance.getActiveEditor().close();\n\n    expect((document.querySelector('#editorComponentContainer') as any).style.display).toEqual('none');\n\n    done();\n  });\n});\n"
  },
  {
    "path": "test/jestsetup.ts",
    "content": "import {\n  configure\n} from 'enzyme';\nimport ReactSixteenAdapter from 'enzyme-adapter-react-16';\n\nconfigure({adapter: new ReactSixteenAdapter()});\n"
  },
  {
    "path": "test/reactContext.spec.tsx",
    "content": "import React from 'react';\nimport {\n  mount,\n  ReactWrapper\n} from 'enzyme';\nimport {\n  HotTable\n} from '../src/hotTable';\nimport {\n  HotColumn\n} from '../src/hotColumn';\nimport {\n  mockElementDimensions,\n  sleep\n} from './_helpers';\nimport { BaseEditorComponent } from '../src/baseEditorComponent';\nimport Handsontable from 'handsontable';\n\nbeforeEach(() => {\n  let container = document.createElement('DIV');\n  container.id = 'hotContainer';\n  document.body.appendChild(container);\n});\n\ndescribe('React Context', () => {\n  it('should be possible to declare a context and use it inside both renderers and editors', async (done) => {\n    let hotTableInstance = null;\n    const TestContext = React.createContext('def-test-val');\n\n    function RendererComponent2() {\n      return (\n        <TestContext.Consumer>\n          {(context) => <>{context}</>}\n        </TestContext.Consumer>\n      );\n    }\n\n    class EditorComponent2 extends BaseEditorComponent {\n      render(): React.ReactElement<string> {\n        return (\n            <TestContext.Consumer>\n              {(context) => <>{context}</>}\n            </TestContext.Consumer>\n        );\n      }\n    }\n\n    class RendererComponent3 extends React.Component {\n      render() {\n        return (\n          <>\n            {this.context}\n          </>\n        )\n      }\n    }\n    RendererComponent3.contextType = TestContext;\n\n    class EditorComponent3 extends React.Component {\n      render() {\n        return (\n          <>\n            {this.context}\n          </>\n        )\n      }\n    }\n    EditorComponent3.contextType = TestContext;\n\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <TestContext.Provider value={'testContextValue'}>\n        <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                  id=\"test-hot\"\n                  data={Handsontable.helper.createSpreadsheetData(3, 2)}\n                  width={300}\n                  height={300}\n                  rowHeights={23}\n                  colWidths={50}\n                  autoRowSize={false}\n                  autoColumnSize={false}\n                  init={function () {\n                    mockElementDimensions(this.rootElement, 300, 300);\n                  }}\n                  ref={function (instance) {\n                    hotTableInstance = instance;\n                  }}>\n          <HotColumn>\n            <RendererComponent2 hot-renderer/>\n            <EditorComponent2 hot-editor className=\"ec2\"/>\n          </HotColumn>\n          <HotColumn>\n            <RendererComponent3 hot-renderer/>\n            <EditorComponent3 hot-editor className=\"ec3\"/>\n          </HotColumn>\n        </HotTable>\n      </TestContext.Provider>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    const hotInstance = hotTableInstance.hotInstance;\n\n    expect(hotInstance.getCell(0, 0).innerHTML).toEqual('<div>testContextValue</div>');\n    expect(hotInstance.getCell(1, 0).innerHTML).toEqual('<div>testContextValue</div>');\n\n    expect(document.querySelector('.ec2').innerHTML).toEqual('testContextValue');\n\n    expect(hotInstance.getCell(0, 1).innerHTML).toEqual('<div>testContextValue</div>');\n    expect(hotInstance.getCell(1, 1).innerHTML).toEqual('<div>testContextValue</div>');\n\n    expect(document.querySelector('.ec3').innerHTML).toEqual('testContextValue');\n\n    wrapper.detach();\n    done();\n  });\n});\n"
  },
  {
    "path": "test/reactHooks.spec.tsx",
    "content": "import React, { useState } from 'react';\nimport {\n  mount,\n  ReactWrapper\n} from 'enzyme';\nimport {\n  HotTable\n} from '../src/hotTable';\nimport {\n  mockElementDimensions,\n  sleep,\n  simulateMouseEvent\n} from './_helpers';\nimport Handsontable from 'handsontable';\n\n\nbeforeEach(() => {\n  let container = document.createElement('DIV');\n  container.id = 'hotContainer';\n  document.body.appendChild(container);\n});\n\ndescribe('Using hooks within HotTable renderers', () => {\n  it('should be possible to use hook-enabled components as renderers', async (done) => {\n    function HookEnabledRenderer(props) {\n      const [count, setCount] = useState(0);\n\n      return (\n        <div className={'hook-enabled-renderer-container'}>\n          <p>{props.value}</p>: <span>{count}</span>\n          <button onClick={() => setCount(count + 1)}>\n            Click me\n          </button>\n        </div>\n      );\n    }\n\n    const wrapper: ReactWrapper<{}, {}, typeof HotTable> = mount(\n      <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                id=\"test-hot\"\n                data={Handsontable.helper.createSpreadsheetData(3, 3)}\n                width={300}\n                height={300}\n                rowHeights={23}\n                colWidths={50}\n                autoRowSize={false}\n                autoColumnSize={false}\n                init={function () {\n                  mockElementDimensions(this.rootElement, 300, 300);\n                }}>\n        <HookEnabledRenderer hot-renderer></HookEnabledRenderer>\n      </HotTable>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    const hotInstance = wrapper.instance().hotInstance;\n\n    expect(hotInstance.getCell(0,0).querySelectorAll('.hook-enabled-renderer-container').length).toEqual(1);\n    expect(hotInstance.getCell(1,1).querySelectorAll('.hook-enabled-renderer-container').length).toEqual(1);\n\n    simulateMouseEvent(hotInstance.getCell(0,0).querySelector('button'), 'click');\n    simulateMouseEvent(hotInstance.getCell(0,0).querySelector('button'), 'click');\n    simulateMouseEvent(hotInstance.getCell(0,0).querySelector('button'), 'click');\n\n    expect(hotInstance.getCell(0,0).querySelector('span').innerHTML).toEqual('3');\n    expect(hotInstance.getCell(1,1).querySelector('span').innerHTML).toEqual('0');\n\n    wrapper.detach();\n    done();\n  });\n});\n\n/*\n Editor components cannot be used with React Hooks, as they need to be classes derived from BaseEditorComponent.\n */\n"
  },
  {
    "path": "test/reactLazy.spec.tsx",
    "content": "import React, { Suspense, lazy } from 'react';\nimport {\n  mount,\n  ReactWrapper\n} from 'enzyme';\nimport {\n  HotTable\n} from '../src/hotTable';\nimport {\n  mockElementDimensions,\n  sleep,\n} from './_helpers';\nimport Handsontable from 'handsontable';\n\nbeforeEach(() => {\n  let container = document.createElement('DIV');\n  container.id = 'hotContainer';\n  document.body.appendChild(container);\n});\n\ndescribe('React.lazy', () => {\n  it('should be possible to lazy-load components and utilize Suspend', async (done) => {\n    function RendererComponent2(props) {\n      return (\n        <>\n          lazy value: {props.value}\n        </>\n      );\n    }\n\n    let promiseResolve = null;\n\n    function SuspendedRenderer(props) {\n      const customImportPromise = new Promise(function (resolve, reject) {\n          promiseResolve = resolve;\n        }\n      ) as any;\n\n      const LazierRenderer = lazy(() => customImportPromise);\n\n      return (\n        <Suspense fallback={<>loading-message</>}>\n          <LazierRenderer {...props}></LazierRenderer>\n        </Suspense>\n      )\n    }\n\n    const wrapper: ReactWrapper<{}, {}, any> = mount(\n      <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                id=\"test-hot\"\n                data={Handsontable.helper.createSpreadsheetData(1, 1)}\n                width={300}\n                height={300}\n                rowHeights={23}\n                colWidths={50}\n                autoRowSize={false}\n                autoColumnSize={false}\n                init={function () {\n                  mockElementDimensions(this.rootElement, 300, 300);\n                }}>\n        <SuspendedRenderer hot-renderer/>\n      </HotTable>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    const hotTableInstance = wrapper.instance();\n    const hotInstance = hotTableInstance.hotInstance;\n\n    expect(hotInstance.getCell(0, 0).innerHTML).toEqual('<div>loading-message</div>');\n\n    promiseResolve({\n      default: RendererComponent2,\n      __esModule: true\n    });\n\n    await sleep(40);\n\n    expect(hotInstance.getCell(0, 0).innerHTML).toEqual('<div>lazy value: A1</div>');\n\n    wrapper.detach();\n\n    done();\n  });\n});\n"
  },
  {
    "path": "test/reactMemo.spec.tsx",
    "content": "import React from 'react';\nimport {\n  mount,\n  ReactWrapper\n} from 'enzyme';\nimport {\n  HotTable\n} from '../src/hotTable';\nimport {\n  mockElementDimensions,\n  sleep,\n} from './_helpers';\nimport Handsontable from 'handsontable';\n\nbeforeEach(() => {\n  let container = document.createElement('DIV');\n  container.id = 'hotContainer';\n  document.body.appendChild(container);\n});\n\n/**\n * Worth noting, that although it's possible to use React.memo on renderer components, it doesn't do much, as currently they're recreated on every\n * Handsontable's `render`.\n */\ndescribe('React.memo', () => {\n  it('should be possible to use React.memo on renderer components.', async (done) => {\n    function RendererComponent2 (props) {\n      return (\n        <>\n        value: {props.value}\n        </>\n      );\n    }\n\n    const MemoizedRendererComponent2 = React.memo(RendererComponent2);\n\n    const wrapper: ReactWrapper<{}, {}, any> = mount(\n      <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                id=\"test-hot\"\n                data={Handsontable.helper.createSpreadsheetData(1, 1)}\n                width={300}\n                height={300}\n                rowHeights={23}\n                colWidths={50}\n                autoRowSize={false}\n                autoColumnSize={false}\n                init={function () {\n                  mockElementDimensions(this.rootElement, 300, 300);\n                }}>\n        <MemoizedRendererComponent2 hot-renderer/>\n      </HotTable>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    const hotTableInstance = wrapper.instance();\n    const hotInstance = hotTableInstance.hotInstance;\n\n    hotInstance.render();\n\n    await sleep(100);\n\n    expect(hotInstance.getCell(0, 0).innerHTML).toEqual('<div>value: A1</div>');\n\n    wrapper.detach();\n\n    done();\n  });\n\n  /*\n    Editors cannot use React.memo, as they're derived from the BaseEditorComponent class, thus not being function components.\n   */\n});\n"
  },
  {
    "path": "test/reactPureComponent.spec.tsx",
    "content": "import React from 'react';\nimport {\n  mount,\n  ReactWrapper\n} from 'enzyme';\nimport {\n  HotTable\n} from '../src/hotTable';\nimport {\n  mockElementDimensions,\n  sleep,\n} from './_helpers';\nimport Handsontable from 'handsontable';\n\nbeforeEach(() => {\n  let container = document.createElement('DIV');\n  container.id = 'hotContainer';\n  document.body.appendChild(container);\n});\n\n/**\n * Worth noting, that although it's possible to use React's Pure Components on renderer components, it doesn't do much, as currently they're recreated on every\n * Handsontable's `render`.\n */\ndescribe('React PureComponents', () => {\n  it('should be possible to declare the renderer as PureComponent', async (done) => {\n    class RendererComponent2 extends React.PureComponent<any, any> {\n      render(): React.ReactElement<string> {\n        return (\n          <>\n            value: {this.props.value}\n          </>\n        );\n      }\n    }\n\n    const wrapper: ReactWrapper<{}, {}, any> = mount(\n      <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                id=\"test-hot\"\n                data={Handsontable.helper.createSpreadsheetData(3, 3)}\n                width={300}\n                height={300}\n                rowHeights={23}\n                colWidths={50}\n                autoRowSize={false}\n                autoColumnSize={false}\n                init={function () {\n                  mockElementDimensions(this.rootElement, 300, 300);\n                }}>\n        <RendererComponent2 hot-renderer/>\n      </HotTable>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    const hotTableInstance = wrapper.instance();\n    const hotInstance = hotTableInstance.hotInstance;\n\n    expect(hotInstance.getCell(0, 0).innerHTML).toEqual('<div>value: A1</div>');\n\n    wrapper.detach();\n\n    done();\n  });\n\n  /*\n    Editors cannot be declared as PureComponents, as they're derived from the BaseEditorComponent class.\n   */\n});\n"
  },
  {
    "path": "test/redux.spec.tsx",
    "content": "import React from 'react';\nimport { createStore, combineReducers } from 'redux';\nimport { Provider, connect } from 'react-redux';\nimport {\n  mount,\n  ReactWrapper\n} from 'enzyme';\nimport {\n  HotTable\n} from '../src/hotTable';\nimport {\n  mockElementDimensions,\n  sleep,\n  RendererComponent,\n  EditorComponent\n} from './_helpers';\nimport Handsontable from 'handsontable';\n\nconst initialReduxStoreState = {\n  hexColor: '#fff'\n};\n\nconst appReducer = (state = initialReduxStoreState, action) => {\n  switch (action.type) {\n    case 'updateColor':\n      const newColor = action.hexColor;\n\n      return Object.assign({}, state, {\n        hexColor: newColor\n      });\n    default:\n      return state;\n  }\n};\nconst actionReducers = combineReducers({appReducer});\nconst reduxStore = createStore(actionReducers);\n\nbeforeEach(() => {\n  let container = document.createElement('DIV');\n  container.id = 'hotContainer';\n  document.body.appendChild(container);\n\n  reduxStore.dispatch({\n    type: 'updateColor',\n    hexColor: '#fff'\n  });\n});\n\ndescribe('Using Redux store within HotTable renderers and editors', () => {\n  it('should be possible to use redux-enabled components as renderers', async (done) => {\n    // let reduxStore = mockStore(initialReduxStoreState);\n\n    const ReduxEnabledRenderer = connect(function (state: any) {\n        return {\n          bgColor: state.appReducer.hexColor\n        }\n      }, () => {\n        return {};\n      },\n      null,\n      {\n        forwardRef: true\n      })(RendererComponent);\n    let rendererInstances = new Map();\n\n    const wrapper: ReactWrapper<{}, {}, any> = mount(\n      <Provider store={reduxStore}>\n        <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                  id=\"test-hot\"\n                  data={Handsontable.helper.createSpreadsheetData(3, 3)}\n                  width={300}\n                  height={300}\n                  rowHeights={23}\n                  colWidths={50}\n                  autoRowSize={false}\n                  autoColumnSize={false}\n                  init={function () {\n                    mockElementDimensions(this.rootElement, 300, 300);\n                  }}>\n          <ReduxEnabledRenderer ref={function (instance) {\n            if (instance === null) {\n              return instance;\n            }\n\n            rendererInstances.set(`${instance.props.row}-${instance.props.col}`, instance);\n          }\n          } hot-renderer />\n        </HotTable>\n      </Provider>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    rendererInstances.forEach((component, key, map) => {\n      expect(component.props.bgColor).toEqual('#fff');\n    });\n\n    reduxStore.dispatch({\n      type: 'updateColor',\n      hexColor: '#B57267'\n    });\n\n    rendererInstances.forEach((component, key, map) => {\n      expect(component.props.bgColor).toEqual('#B57267');\n    });\n\n    wrapper.detach();\n\n    done();\n  });\n\n  it('should be possible to use redux-enabled components as editors', async (done) => {\n    const ReduxEnabledEditor = connect(function (state: any) {\n        return {\n          bgColor: state.appReducer.hexColor\n        }\n      }, () => {\n        return {};\n      },\n      null,\n      {\n        forwardRef: true\n      })(EditorComponent);\n    let editorInstances = new Map();\n\n    const wrapper: ReactWrapper<{}, {}, any> = mount(\n      <Provider store={reduxStore}>\n        <HotTable licenseKey=\"non-commercial-and-evaluation\"\n                  id=\"test-hot\"\n                  data={Handsontable.helper.createSpreadsheetData(3, 3)}\n                  width={300}\n                  height={300}\n                  rowHeights={23}\n                  colWidths={50}\n                  init={function () {\n                    mockElementDimensions(this.rootElement, 300, 300);\n                  }}>\n          <ReduxEnabledEditor ref={function (instance) {\n            if (instance === null) {\n              return instance;\n            }\n\n            editorInstances.set(`${instance.props.row}-${instance.props.col}`, instance);\n          }\n          } hot-editor />\n        </HotTable>\n      </Provider>, {attachTo: document.body.querySelector('#hotContainer')}\n    );\n\n    await sleep(100);\n\n    editorInstances.forEach((value, key, map) => {\n      expect(value.props.bgColor).toEqual('#fff');\n    });\n\n    reduxStore.dispatch({\n      type: 'updateColor',\n      hexColor: '#B57267'\n    });\n\n    editorInstances.forEach((value, key, map) => {\n      expect(value.props.bgColor).toEqual('#B57267');\n    });\n\n    wrapper.detach();\n\n    done();\n  });\n});\n"
  },
  {
    "path": "test/settingsMapper.spec.tsx",
    "content": "import { SettingsMapper } from '../src/settingsMapper';\nimport { HotTableProps } from '../src/types';\n\ndescribe('Settings mapper unit tests', () => {\n  describe('getSettings', () => {\n    it('should return a valid settings object, when provided an object with settings (including the hooks prefixed with \"on\")', () => {\n      const settingsMapper = new SettingsMapper();\n\n      const initial: HotTableProps = {\n        width: 300,\n        height: 300,\n        contextMenu: true,\n        columns: [\n          {label: 'first label'},\n          {label: 'second label'}\n        ],\n        afterChange: () => {\n          return 'works!';\n        },\n        afterRender: () => {\n          return 'also works!';\n        }\n      };\n      const result: {[key: string]: any} = SettingsMapper.getSettings(initial);\n\n      expect(!!result.width && !!result.height && !!result.contextMenu && !!result.columns && !!result.afterChange && !!result.afterRender).toEqual(true);\n      expect(Object.keys(initial).length).toEqual(Object.keys(result).length);\n      expect(result.width).toEqual(300);\n      expect(result.height).toEqual(300);\n      expect(result.contextMenu).toEqual(true);\n      expect(JSON.stringify(initial.columns)).toEqual(JSON.stringify(result.columns));\n      expect(JSON.stringify(result.afterChange)).toEqual(JSON.stringify(initial.afterChange));\n      expect(JSON.stringify(result.afterRender)).toEqual(JSON.stringify(initial.afterRender));\n      expect(result.afterChange()).toEqual('works!');\n      expect(result.afterRender()).toEqual('also works!');\n    });\n\n    it('should return a valid settings object, when provided an object with settings inside a \"settings\" property (including the hooks prefixed with \"on\")', () => {\n      const settingsMapper = new SettingsMapper();\n      const initial = {\n        settings: {\n          width: 300,\n          height: 300,\n          contextMenu: true,\n          columns: [\n            {label: 'first label'},\n            {label: 'second label'}\n          ],\n          afterChange: () => {\n            return 'works!';\n          },\n          afterRender: () => {\n            return 'also works!';\n          }\n        }\n      };\n      const result: {[key: string]: any} = SettingsMapper.getSettings(initial);\n\n      expect(!!result.width && !!result.height && !!result.contextMenu && !!result.columns && !!result.afterChange && !!result.afterRender).toEqual(true);\n      expect(Object.keys(initial.settings).length).toEqual(Object.keys(result).length);\n      expect(result.width).toEqual(300);\n      expect(result.height).toEqual(300);\n      expect(result.contextMenu).toEqual(true);\n      expect(JSON.stringify(initial.settings.columns)).toEqual(JSON.stringify(result.columns));\n      expect(JSON.stringify(result.afterChange)).toEqual(JSON.stringify(initial.settings.afterChange));\n      expect(JSON.stringify(result.afterRender)).toEqual(JSON.stringify(initial.settings.afterRender));\n      expect(result.afterChange()).toEqual('works!');\n      expect(result.afterRender()).toEqual('also works!');\n      expect(result.settings).toEqual(void 0);\n    });\n\n    it('should return a valid settings object, when provided an object with settings inside a \"settings\" property as well as individually (including the hooks prefixed with \"on\")', () => {\n      const settingsMapper = new SettingsMapper();\n      const initial = {\n        width: 300,\n        height: 300,\n        settings: {\n          contextMenu: true,\n          columns: [\n            {label: 'first label'},\n            {label: 'second label'}\n          ],\n          afterChange: () => {\n            return 'works!';\n          },\n          afterRender: () => {\n            return 'also works!';\n          }\n        }\n      };\n      const result: {[key: string]: any} = SettingsMapper.getSettings(initial);\n\n      expect(!!result.width && !!result.height && !!result.contextMenu && !!result.columns && !!result.afterChange && !!result.afterRender).toEqual(true);\n      expect(Object.keys(initial.settings).length + Object.keys(initial).length - 1).toEqual(Object.keys(result).length);\n      expect(result.width).toEqual(300);\n      expect(result.height).toEqual(300);\n      expect(result.contextMenu).toEqual(true);\n      expect(JSON.stringify(initial.settings.columns)).toEqual(JSON.stringify(result.columns));\n      expect(JSON.stringify(result.afterChange)).toEqual(JSON.stringify(initial.settings.afterChange));\n      expect(JSON.stringify(result.afterRender)).toEqual(JSON.stringify(initial.settings.afterRender));\n      expect(result.afterChange()).toEqual('works!');\n      expect(result.afterRender()).toEqual('also works!');\n      expect(result.settings).toEqual(void 0);\n    });\n  });\n});\n"
  },
  {
    "path": "test-tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"moduleResolution\": \"node\",\n    \"target\": \"esnext\",\n    \"jsx\": \"react\",\n    \"module\": \"esnext\",\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"baseUrl\": \".\"\n  }\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"esnext\",\n    \"jsx\": \"react\",\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"sourceMap\": true,\n    \"baseUrl\": \".\",\n    \"declarationDir\": \".\"\n  },\n  \"include\": [\n    \"src/*\"\n  ],\n  \"exclude\": [\n    \"**/node_modules/*\"\n  ]\n}\n"
  }
]