[
  {
    "path": ".alexignore",
    "content": "# The Code of Conduct calls out language that can't be used so it's not linted.\nCODE_OF_CONDUCT.md\n\n# The CHANGELOG contains references to commit messages.\nCHANGELOG.md\n\n# We will handle meeting notes and roadmap documents after the main docs are linted.\nmeta/meeting-notes/**/*.md\nmeta/roadmaps/*.md\n\n# This README contains some domain specific language that fails validation.\nexamples/draft-0-10-0/playground/README.md"
  },
  {
    "path": ".alexrc.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nexports.allow = [\n  // We frequently refer to form props by their name \"disabled\".\n  // Ideally we would alex-ignore only the valid uses (PRs accepted).\n  \"invalid\",\n\n  // Unfortunately \"watchman\" is a library name that we depend on.\n  \"watchman-watchwoman\"\n];\n\n// Use a \"maybe\" level of profanity instead of the default \"unlikely\".\nexports.profanitySureness = 1;"
  },
  {
    "path": ".dependabot/config.yml",
    "content": "version: 1\nupdate_configs:\n  - package_manager: \"javascript\"\n    directory: \"/examples/draft-0-10-0/playground\"\n    update_schedule: \"monthly\"\n  - package_manager: \"javascript\"\n    directory: \"/examples/draft-0-10-0/tex\"\n    update_schedule: \"monthly\"\n  - package_manager: \"javascript\"\n    directory: \"/examples/draft-0-10-0/universal\"\n    update_schedule: \"monthly\"\n  - package_manager: \"javascript\"\n    directory: \"/\"\n    update_schedule: \"weekly\"\n"
  },
  {
    "path": ".eslintignore",
    "content": "lib/\ndist/\ndocs/\nnode_modules/\nwebsite/\ngulpfile.js\nscripts/module-map.js\nscripts/jest/preprocessor.js\nscripts/jest/hasteImpl.js\nexamples/draft-0-10-0/universal/static/bundle.js\nexamples/draft-0-9-1/universal/static/bundle.js\n"
  },
  {
    "path": ".eslintrc.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nmodule.exports = {\n  extends: [\n    'fbjs',\n    'prettier',\n    'prettier/flowtype',\n    'prettier/react',\n    'prettier/standard',\n  ],\n  rules: {\n    'prettier/prettier': ['error'],\n  },\n  plugins: ['prettier', 'fb-www'],\n  overrides: [\n    {\n      files: ['examples/draft-0-10-0/**', 'examples/draft-0-9-1/**'],\n      rules: {\n        'prettier/prettier': 0,\n        'jsx-a11y/no-static-element-interactions': 0,\n        'no-console': 0,\n      },\n    },\n  ],\n};\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "#### Do you want to request a *feature* or report a *bug*?\n\n#### What is the current behavior?\n\n#### If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. You can use this jsfiddle to get started: https://jsfiddle.net/gmertk/e61z7nfa/.\n\n#### What is the expected behavior?\n\n#### Which versions of Draft.js, and which browser / OS are affected by this issue? Did this work in previous versions of Draft.js?\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "*Before* submitting a pull request, please make sure the following is done...\n\n1. Fork the repo and create your branch from `master`.\n2. If you've added code that should be tested, add tests!\n3. If you've changed APIs, update the documentation.\n4. Ensure that:\n  * The test suite passes (`npm test`)\n  * Your code lints (`npm run lint`) and passes Flow (`npm run flow`)\n  * You have followed the [testing guidelines](https://github.com/facebook/draft-js/wiki/Testing-for-Pull-Requests)\n5. If you haven't already, complete the [CLA](https://code.facebook.com/cla).\n\nPlease use the simple form below as a guideline for describing your pull request, and delete these instructions.\n\nThanks for contributing to Draft.js!\n\n---\n\n#### Summary\n\n[...]\n\n#### Test Plan**\n\n[...]\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\non: [push, pull_request]\n\njobs:\n  ci:\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        node-version: ['14', '16']\n        cmd: ['build']\n    steps:\n      - uses: actions/checkout@v2\n      - name: Use Node.js ${{ matrix.node-version }}\n        uses: actions/setup-node@v2\n        with:\n          node-version: ${{ matrix.node-version }}\n          cache: 'yarn'\n      - name: Install dependencies\n        run: yarn install --frozen-lockfile\n      - name: Run ${{ matrix.cmd }}\n        run: yarn run ${{ matrix.cmd }}\n"
  },
  {
    "path": ".gitignore",
    "content": "static/\ndist/\nlib/\nbuild/\nnode_modules\nwebsite/src/docs/\nnpm-debug.log\n!website/static/\nyarn-error.log\n.DS_Store\nmeta/bundle-size-stats/\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nNotable changes to Draft.js will be documented in this file.\n\nChanges to `src` are live in production on facebook.com at the time of release.\n\n## 0.11.7 (Aug 13th, 2020)\n\n### Added\n\n* Allow aria-describedby overriding (Jeff Dickey in 8b8b9c00)\n* Add support to create editor state using text string (Abhishek Pandya in fc9395fe)\n\n### Changed\n* Update readme to suggest building with yarn (#2527) (Kevin Chavez in 54213a13)\n* Update build, static analysis deps (+ upgrade to fbjs 2.0.0) (#2541) (Kevin Chavez in 5e92a32f)\n* Tex example: Update babel to v7 + other deps (#2533) (Kevin Chavez in ce94ecf3)\n* Update package.json (#2490) (Michaël De Boey in b79082f9)\n* Update media.html (#2452) (fay in a8f44b15)\n* Upgrade dependencies in playground example (#2534) (Kevin Chavez in f6bf4ed3)\n* feat(docs): Update README.md (#2523) (Darsh Shah in e0fc33eb)\n* adds highlight in docs (#2469) (Tunde Thomas in cef61910)\n* Update QuickStart-API-Basics.md (#2491) (Michaël De Boey in 170fe23a)\n* Update .travis.yml (#2495) (Michaël De Boey in 3eb391e7)\n* Update link to Record in docs (#2418) (Rounak Agarwal in 6a55c383)\n* Update link to Immutable Map in docs (#2530) (Rounak Agarwal in 31dde91a)\n* Upgrade browserify and babel deps in universal example (#2532) (Kevin Chavez in 1c8815a1)\n* Upgrade eslint, flow, jest (#2531) (Kevin Chavez in ccd0470b)\n* Fix the build by adding an argument to catch statement (Kevin Chavez in 5482c902)\n* Conditionally invokes URI.tryParseURI in OSS code (Claudio Procida in 36de6f1f)\n* formatPastedText prop (Laura González in 9a9ccbd5)\n* fix pasting invalid links (Frank Thompson in 862a5b2b)\n* chore(dependabot): adds examples directories separately (#2505) (Claudio Procida in fb0eb34c)\n* style(website): Removes desaturation (#2504) (Claudio Procida in 2b8edb18)\n* Fixes links accessibility by adding underlines (#2497) (R Nabors in 5e17cc24)\n* add codes to suppressions in www (Daniel Sainati in 8457ebba)\n* update comments in mobile to support error codes (Daniel Sainati in fb728fde)\n* Use object shorthand in DraftEditorCompositionHandler (Kevin Chavez in d949433d)\n* Force the selection when composition is resolved (#2094) (Robbert Brak in 3be4d372)\n* fix(security): Upgrades Docusaurus to address CVE-2020-7662 (#2457) (Claudio Procida in a08a8fa5)\n\n\n## 0.11.6 (June 4th, 2020)\n\n### Added\n* Adds BLM banner (#2454) (claudiopro in 2a0c5bbe)\n* HtmlConversion: Add support for telephone links (#2365) (Andrew Lauria in e1e9a0c5)\n* 7.C - Block Operations - Consume (Shalabh Vyas in 99c6b06c)\n* Add fromJS() API to Draft model objects (Shalabh Vyas in 3ee5a23e)\n\n### Changed\n* Add Null return value type in code example (#2429) (Jacob D. Castro in 45bb6b52)\n* Add /meta/bundle-size-stats to .gitignore (#2436) (Kevin Chavez in e3a689df)\n* Update eslint, cross-env and gulp-derequire. Fix version numbers for … (#2437) (Kevin Chavez in 79a25b5c)\n* Update Overview.md (#2434) (Mohamed ABDELLANI in e5e293f1)\n* Upgrade jest and flow-bin deps (#2435) (Kevin Chavez in 9ac399cc)\n* Update cadence for dependabot updates (#2402) (Kevin Chavez in 6619077c)\n* Bump alex from 8.0.0 to 8.1.1 (#2407) (dependabot-preview[bot] in 7e604b06)\n* Bump fstream from 1.0.11 to 1.0.12 in /examples/draft-0-10-0/tex (#2396) (dependabot[bot] in 1f5d40ec)\n* Bump acorn from 6.0.5 to 6.4.1 in /examples/draft-0-10-0/tex (#2376) (dependabot[bot] in 9028881c)\n* chore(flow): Updates flow-bin to 0.123 (#2393) (Claudio Procida in 497a4787)\n* Short-circuit getUpdatedSelectionState for invalid selection updates on prod (Kevin Chavez in 0585b68f)\n* Type selection object in setDraftEditorSelection.js (Kevin Chavez in 31dec710)\n* Type selection object in keyCommandBackspaceToStartOfLine.js (Kevin Chavez in aa5c4a19)\n* Flow v0.123.0 in www (Panagiotis Vekris in af675755)\n* Type selection object in getDraftEditorSelection.js (Kevin Chavez in dfacb1b4)\n* Type selection object in editOnBlur.js (Kevin Chavez in 22997144)\n* Type selection object in editOnInput. (Kevin Chavez in 41beae1b)\n* upgrade to flow 0.122.0 (Marshall Roch in 97dd19b2)\n* DraftEntity ID Changes (Shalabh Vyas in 13989e31)\n* use pasted block type if pasting to empty unstyled block (Frank Thompson in 7d3d3c8f)\n* Update deps for and cleanup playground example (#2368) (Kevin Chavez in 2658dd60)\n* Only extend selection if it has ranges in setDraftEditorSelection.js (Kevin Chavez in d53fa7ab)\n* Update draft.js on website to v0.11.5 (#2370) (Kevin Chavez in 538d864e)\n* Make a few types exact (Kevin Chavez in 0950285d)\n* Remaining non-generated non-reason-parsed files (Jordan Brown in 153482ff)\n\n### Fixed\n* Fix draft-js pasted inline styles (Giulio Jiang in 92176ab2)\n* docs: in react hooks example, limit createEmpty calls (#2432) (Benjamin Atkin in 05e838e6)\n* Revisit comment for todo of T65805998, validate there's nothing to worry about (Kevin Chavez in 268ece35)\n* html/shared/draft-js/model/transaction (generatedunixname89002005287564 in c75f1e4c)\n* types-first in html/js/mobile (Panagiotis Vekris in e66f39ef)\n* Address #2413 by making Firefox follow the same behaviour as Chrome (#2414) (Kevin Chavez in 6d619c61)\n* Prevent placeholder from unnecessarily wrapping (#2392) (Frank Yan in 9d6bbfdc)\n* docs: Fix simple typo, sibbling -> sibling (#2384) (Tim Gates in d1cb1e77)\n* Fix build by adding missing modules (Kevin Chavez in fbe3417e)\n* Fix flow by allowing optional chaining (#2369) (Kevin Chavez in 85764327)\n\n## 0.11.5 (Mar 26, 2020)\n\n### Removed\n* Remove examples for draft.js 0.9.0 (#2358) (Kevin Chavez in fd16d8e2)\n\n### Changed\n* Update deps in 'universal' example (#2362) (Kevin Chavez in dc8bfbb2)\n* Remove unused Flow suppressions in WWW (George Zahariev in 3858858b)\n* Improve types for EditorState (Kevin Chavez in 792bd3ab)\n* Don't SSR example editor on website. (#2356) (Kevin Chavez in 9191a3f2)\n* Deprecate Travis Bot files and configuration (Chris Lüer in 6c1c6544)\n* Require ReactDOMComet instead of ReactDOM (Dan Abramov in 66301633)\n* Strictify DraftEditorLeaf.react.js (Kevin Chavez in b4a1db99)\n* Make decodeEntityRanges flow strict (Kevin Chavez in 7af73b70)\n* Move key to static argument instead of spread (Sebastian Markbage in d6527a95)\n* \"ecmascript\" => \"ECMAScript\" (#2327) (Agastya Chandrakant in 6cfed736)\n* Abstract ReactDOM as ReactDOMComet (Sebastian Markbage in 24339f12)\n* Prevent (but not fix) ‘Cannot read property 'getIn' of undefined’ in getUpdatedSelectionState (Steven Luscher in a9fcbb20)\n* Make some more modules strict(-local) (Kevin Chavez in c30ca735 and 70025659)\n* Update webpack deps (#2310) (Kevin Chavez in 0131e1d5)\n* Remove unused gulp task remained from docusaurus 2 migration (#2308) (Kanitkorn S in 963e3126)\n* Re-write `DraftEditorExample` in the website using react hooks (#2287) (Kevin Chavez in 9b9376bd)\n* Add a preventScroll prop (Dan Abramov in 3ba907bb)\n* Add editorRef prop to DraftEditor (Dan Abramov in 8c500424)\n* Remove findDOMNode from DraftEditorBlockNode (Sebastian Markbage in 0dd39781)\n* Remove findDOMNode in DraftEditorDragHandler (Sebastian Markbage in c1a55ceb)\n* Remove findDOMNode from getContentEditableContainer (Sebastian Markbage in 9d587d9f)\n* Upgrade to Flow explicit inexact object type syntax (Jordan Brown in b051fc1b)\n* Upgrade eslint + flow, and fix failed test from nullishCoalescingOperator (#2083) (Kanitkorn S in 824fd125)\n* chore(travis): bumps node versions used in Travis CI to 10 and 12 (#2300) (Claudio Procida in e711230f)\n\n### Fixed\n* Fix Uncaught TypeError: Cannot read property 'nodeType' of null at editOnInput (#2330) (Konstantin Tarkus in db3216d9)\n* Fix keyBindingFn documentation URL (Ryan Silva in 3251017d)\n* fix style handling in convertFromHTMLToContentBlocks (Frank Thompson in ad8374d2)\n* remove unused flow suppressions (Panagiotis Vekris in 822d2fbd)\n\n## 0.11.4 (January 7th, 2020)\n\n### Added\n* Add Section and Article to DefaultBlockRenderMap (#2212) (Tarun047 in e20f79f)\n\n### Changed\n* Add rules to .flowconfig for flow strict rules (#2288) (Kevin Chavez in f223799)\n* Update website's yarn version to 0.11.3 (Kevin Chavez in efcaf42)\n* Prettify docs files (#2275) (Yangshun Tay in 6fc9964)\n* Remove Jest auto mocking (#2279) (Yangshun Tay in 817e371)\n* Add myself to get TravisCI emails (Kevin Chavez in f4167fe)\n* Unit tests for isHTMLBRElement (Claudio Procida in bb81765)\n* Remove niveditc from Travis CI email (Nivedita Chopra in 7721805)\n* Create CNAME (#2276) (Yangshun Tay in 92680be)\n* Upgrade to Docusaurus 2 (#2268) (Yangshun Tay in 5b10191)\n* move alex to dev dependencies (#2272) (Ilya in b889d5d)\n* Improve docs syntax and formatting (#2267) (Yangshun Tay in 9b4a628)\n\n### Fixed\n* fix(chore): fixes webpack-stream error with missing catch var declaration (#2291) (Claudio Procida in 4252469)\n* IE could not display composer when opening or creating a new group chat from the chat create view (Jainil Parekh in 64b51df)\n* Fix DOMObserver mutation data for IE (#2285) (Jainil Parekh in afb708f)\n* Added tests and fixed IE IndexSizeError trying to get a range from a selection when there is not one (#2271) (Lauren Wyatt in aa55de2)\n* Fix scroll behavior when node has tab chars (#2256) (cdr in 5d37c03)\n* Fix docs links in readme (#2284) (Lucas Cordeiro in 3b6d231)\n* Fix isHTMLBRElement test (#2278) (Yangshun Tay in 0603772)\n* Fix `isHTMLBRElement` check (Jack Armstrong in e869fcb)\n* Fix typing Chinese in Edge (#2082) (#2088) (Robbert Brak in 8c0727e)\n* Fix Travis website deployment (#2274) (Yangshun Tay in 861aab8)\n* getEntityKeyForSelection.js (Kevin Chavez in c07a404)\n\n## 0.11.3 (December 2nd, 2019)\n\n### Added\n* Take over enhancements to render Draft.js in an iframe (#1938) (Claudio Procida in dceddf5)\n* Implement click listener for editor wrapper (#2230) (Max Vyz in 8f77aa3)\n* Add linting for insensitive and inconsiderate language (#2223) (Claudio Procida in 5dd99d3)\n\n### Changed\n* Updates to Prettier 1.19.1 (#2265) (Claudio Procida in abcbe20)\n* Bump mixin-deep from 1.3.1 to 1.3.2 in /examples/draft-0-10-0/universal (#2259) (dependabot[bot] in 37d281b)\n* Upgrade dependencies in /website (#2263) (Kevin Chavez in 0b57720)\n* Update dependencies in examples/draft-0-10-0/universal (#2257) (Kevin Chavez in ae2dd14)\n* Update dependencies in examples/draft-0-10-0/playground (#2258) (Kevin Chavez in 11bc5d8)\n* Prettify files rest of non-intern files in html/ (George Zahariev in 6217dc8)\n* add flow declaration in editOnBeforeInput-test.js (Frank Thompson in 0601090)\n* Bump lodash.merge from 4.6.1 to 4.6.2 in /website (#2241) (dependabot[bot] in 177db5e)\n* Defaulting to createEmpty if block map is empty in createWithContent (Fixes issue #2226) (#2240) (David Fuentes in c42662e)\n* Bump handlebars from 4.1.1 to 4.5.1 in /examples/draft-0-10-0/playground (#2242) (dependabot[bot] in 2a761af)\n* Suppress non-synced files in www for 0.111 (Jordan Brown in 4bca140)\n* Upgrade more deps. (#2239) (Kevin Chavez in a477e83)\n* Bump lodash.template from 4.4.0 to 4.5.0 in /examples/draft-0-10-0/playground (#2236) (dependabot[bot] in 0e03745)\n* Bump mixin-deep from 1.3.1 to 1.3.2 in /website (#2234) (dependabot[bot] in 78f20cc)\n* Bump lodash from 4.17.11 to 4.17.15 in /website (#2233) (dependabot[bot] in da1ab7c)\n* Updated browser icons in README (#2238) (SuNNjek in 6ed6ed4)\n* Bump mixin-deep from 1.3.1 to 1.3.2 in /examples/draft-0-10-0/playground (#2235) (dependabot[bot] in 2744ff7)\n* Upgrade 8 dependencies (including jest, @babel/core, etc). (#2237) (Kevin Chavez in 46103ac)\n* Upgrades ESLint and related plugins/configs. (#2231) (Kevin Chavez in 53d2a63)\n\n### Fixed\n* fix wrong property access in convertFromHTMLToContentBlocks (Frank Thompson in 7d26fab)\n* Fix draftjs type error for event (Jack Armstrong in e7ae2e7)\n* fix decorator handling in editOnBeforeInput (Frank Thompson in 1452b87)\n* fixes #304, kudos to @andpor (#2197) (Ante Beslic in 2908035)\n* Fix playground example import (#2220) (Ryan Lee in 778e88d)\n* Fix React warnings (#2221) (Alan Norbauer in 2595016)\n\n### Meta\n* deploy v112 to www (Daniel Sainati in ae542b7)\n\n## 0.11.2 (September 30th, 2019)\n\n### Changed\n\n* Upgrade to Flow strict-local (generatedunixname89002005287564 in 0c92bf7)\n* chore(website): updates stylesheet for 0.11.1 (#2188) (Claudio Procida in 543df66)\n* Prepare 0.11.1 (#2186) (Claudio Procida in 3adf593)\n\n### Fixed\n\n* fix(selection): Returns previous selection if either leaf is null (#2189) (Claudio Procida in fe68e43)\n\n## 0.11.1 (September 19th, 2019)\n\n### Added\n* Support post processor on paste entities. (Tee Xie in 3043573)\n* Adding 'preserveSelectionOnBlur' prop (#2128) (Matthew Holloway in db792ef)\n\n### Changed\n* Reaping draft_segmented_entities_behavior (Mohamed Moussa in cd4adaa)\n* Make insertIntoList strict-local (Kevin Chavez in db64f93)\n* Adopt Contributor Covenant (Paul O'Shannessy in 2c61167)\n* Flowify editOnKeyDown.js (Kevin Chavez in 8473e41)\n* (Flowify) decodeInlineStyleRanges.js (Kevin Chavez in 20a619c)\n* Flowify editOnInput.js (Kevin Chavez in 594a14f)\n* Flowify editOnBlur.js (Kevin Chavez in 6972278)\n* updated function description for onEditInput event handler function (#2132) (Mukesh Soni in 14349f1)\n* updated hastext method to not account for zero space width chars (#2163) (Ajith V in 85aa3a3)\n* Encode non-ASCII characters in all snapshot tests (Daniel Lo Nigro in 734bd82)\n* @flow -> @flow-strict for html/shared (Runjie Guan in 0375c0e)\n* Revert D16421104: [rfc][draft-js] catch errors when encoding entity map (Frank Thompson in 8e9cabf)\n* catch errors when encoding entity map (Frank Thompson in 259d122)\n* Revert D16362778: [rfc][draftjs] catch errors when encoding entity map (Frank Thompson in 96e7f25)\n* catch errors when encoding entity map (Frank Thompson in c0e911c)\n* Flow-type DataTransfer.js (Kevin Chavez in ed09f78)\n* All these modules can actually be strict (Kevin Chavez in bc716b2)\n\n### Fixed\n* convertFromHTML breaks after converting \\n string, issue #1822 (#1823) (Sannikov in 9246cc7)\n* Fixes HTML importer to make image entity immutable (#2184) (Claudio Procida in b858f43)\n* Fixing js example and cleaning up one sentence (#2172) (Liz LeCrone in 819f58c)\n* Reaping draft_killswitch_allow_nontextnodes (generatedunixname89002005287564 in 0e2e9a7)\n* Fix for workchat composer cursor jumping (Jainil Parekh in aed35d2)\n* Fix various grammatical errors (#2158) (Jordan Lee in 1ff8c8c)\n* Composer: Not assuming element has leaves (Nitzan Raz in ce8bdd0)\n* Update jsfiddle links with recent versions of the Draft and React (#2145) (Günay Mert Karadoğan in 22b7599)\n* Changes reference to BSD license to MIT (#2130) (claudiopro in 4064cae)\n* Updates CHANGELOG for v0.11.0 (#2052) (Claudio Procida in 973f7ff)\n* Fixed a bug causing block data being over-written when pasted. (Tee Xie in 82e2135)\n* Merge pull request #2113 from danielo515/patch-1 (Claudio Procida in 0e88544)\n* Update ShipIt Sync (Claudio Procida in 0f138d1)\n\n## 0.11.0 (July 9th, 2019)\n\n### Added\n* Adds support for nullish coalescing operator (#2076) (Claudio Procida in 96c7221)\n* Add import statements for hooks-example in README (#2075) (Bennett in 943f6dc)\n* Unit tests for DraftStringKey (Claudio Procida in 978ad6b)\n* Adding Hooks in docs (#2004) (Charles ⚡ in f9f5fd6)\n* Exports `isSoftNewlineEvent` as static method of `KeyBindingUtil` (Kevin Hawkinson in aede823)\n* Add live demo to README.md (#1907) (PLa in 6db3726)\n* added highlighting (`<mark>` tag) to draft js html to content block converter (Isaiah Solomon in 37f2f2a)\n* Relicense under MIT and remove patents grant (#1967) (Claudio Procida in 585af35)\n* Ctrl-K at end of line should delete newline (Sophie Alpert in 6455493)\n* Add type annotations to `React.Component` classes in html/shared (Paco Estevez Garcia in 2e3a181)\n* Add return type annotation to `addEmojiInput` (Sam Goldman in 280d242)\n* Unstyle empty list item on Enter key (#769) (Eric Biewener in a0267a9)\n* Allow Option+Space to be handled on OSX Chrome (#1254) (Colin Jeanne in 022bcf7)\n* Added information about nature of block keys (#1892) (Prateek Nayak in 8ad59c4)\n* Add flow to files (Nivedita Chopra in d87e093)\n* Docs: add explicit deprecation notes to Entity methods (#1787) (vinogradov in cc6b897)\n* Clarifies editor example, changes height to min-height (#1889) (Claudio Procida in 67d6fda)\n* Improves editor overview example with min height and border (#1887) (Claudio Procida in b8862fd)\n* Adds iframed editor example (#1879) (Claudio Procida in 8d5cbbe)\n* Perform untab on backspace for nested items (Nivedita Chopra in 0688fa3)\n* Support custom block rendering (Nivedita Chopra in fbe2267)\n* Updates favicons and launcher icons with Draftjs logo (#1872) (Claudio Procida in d9c9d40)\n* Merge successive non-leaf blocks resulting from tab (Nivedita Chopra in fbd18ce)\n* Merge successive non-leaf blocks resulting from untab (Nivedita Chopra in 36e588a)\n* Unnest the first non-leaf child (Nivedita Chopra in 0cb3804)\n* Implement untab operations (Nivedita Chopra in 77e6844)\n* added favicon (#1871) (saranshkataria in b9dd551)\n* Add Algolia search (#1864) (Yangshun Tay in 1bf2145)\n* `KeyBindingUtil`: add `usesMacOSHeuristics` method (#869) (William Boman in 98e7730)\n* Export `RawDraftContentState` publicly (#1841) (Cédric Messiant in c6ff39d)\n* Implement moveChildUp operation for untab (Nivedita Chopra in e145a2a)\n* Allow insertion at a specific point for updateParentChild (Nivedita Chopra in 6b83312)\n* Implement onTab in NestedRichTextEditorUtil (Nivedita Chopra in 8d3cfba)\n* Add utilty methods for creating a new parent & updating node to become sibling's child (Nivedita Chopra in 6f73657)\n* Add utility methods for parent-child & sibling pointer updates (Nivedita Chopra in 0cb80b7)\n* Warn visibly when extensions break Draft (Sophie Alpert in c0fb6a8)\n* Add data structure invariants for tree data (Nivedita Chopra in ad4f64f)\n* Add Draft.js logo to header (Joel Marcey in 0ce20bc)\n* Enable deprecated-type rule in www (George Zahariev in dc9fa27)\n* Add different counter-style for ordered lists based on their depth (Noam Elboim in d2a3ae8)\n* Finish modernizing `convertFromHTMLToContentBlocks` - max nesting bug fix (Noam Elboim in 06c0ee6)\n* Finish modernizing `convertFromHTMLToContentBlocks` - upgrade draft-js internals (Noam Elboim in d24b802)\n* Finish modernizing `convertFromHTMLToContentBlocks` - nesting bug fix (Noam Elboim in 49bdd85)\n* Add docs about `DraftDecoratorComponentProps` (Flarnie Marchan in 7fddfcd)\n* Add list block `onTab` test (il kwon Sim in 102701c)\n* Integrating experiments on playground (mitermayer in b6ae887)\n* Add clarifying comments to `getRemovalRange` (Flarnie Marchan in 28cb4a3)\n* Adding Rich Editor to the playground (mitermayer in 227d125)\n* Allow indentation beyond one level deeper than block above. (Eric Biewener in 73e5a9c)\n* Enabling a GK manager for the plaground (mitermayer in 8eea2c2)\n* Bundle size stats (Alan in 5ffce3d)\n* Clear block type when pressing backspace (Sophie Alpert in 6a1e2b0)\n* added favicon to website (Michael Baldwin in 6cc2d85)\n* expose start/end positions of a decorated component within a contentBlock (Matthew Mans in 3a3d34b)\n* Add draft js playground (Julian Krispel-Samsel in 18fdffb)\n\n\n### Changed\n* Moves test for legacy convertFromHTMLToContentBlocks out of OSS repo (Claudio Procida in 5eb49b1)\n* Removes legacy convertFromHTMLToContentBlocks from OSS repo (Claudio Procida in a7d955e)\n* Renames convertFromHTMLToContentBlocks2 to convertFromHTMLToContentBlocks (Claudio Procida in d08399b)\n* Removes all resolved uses of convertFromHTMLToContentBlocks_DEPRECATED (Claudio Procida in ec43403)\n* draft-js: clean up useless divs from HTML when pasting content (Daniel Quadros de Miranda in 0f5427a)\n* docs: remove --save flag (#2008) (Mounish Sai in f92d4b1)\n* Rename DraftEditorBlock to EditorBlock (#2002) (Umang Galaiya in 8514b57)\n* Removes unnecessary eslint disable rules (Claudio Procida in 1ba0764)\n* Upgrades react-scripts to ^1.1.5 (#2042) (Claudio Procida in 71ef373)\n* Upgrades docusaurus (#2039) (Claudio Procida in 21753fa)\n* Removes unused gulp-browserify-thin (#2032) (Claudio Procida in fc3549a)\n* Upgrades @babel/core, babel-preset-fbjs, and gulp-util (#2028) (Claudio Procida in 68196f6)\n* Deploy 0.94 to www (George Zahariev in 6183935)\n* deploy 0.93 (Daniel Sainati in 3400cda)\n* Normalize case in `convertFromHTMLToContentBlocks` variable names (Claudio Procida in b4183b1)\n* Cleans up and refreshes generated website resources (#1998) (Claudio Procida in bd799f5)\n* Upgrades Draft to React 16.8 ⚛️ (#1996) (claudiopro in a97ed7e)\n* Adds email notifications for TravisCI builds (#1990) (Claudio Procida in a4cc10d)\n* Upgrades flow-bin to 0.91.0 and mutes fbjs joinClasses error � (#1989) (Claudio Procida in e8a281c)\n* Update to 0.92.0 (Paco Estevez Garcia in c022efb)\n* Update webpack-dev-server & babel version in TeX examples (#1981) (Nivedita Chopra in a3a3585)\n* Remove `componentWillReceiveProps` usages in examples (#1952) (Deep in 363f66e)\n* Upgrade to Gulp 4 (fixes build) (#1957) (Kevin Chavez in 85ad25c)\n* Kill permanent permanently. (Andrey Sukhachev in 236270a)\n* Deploy Flow v0.85 to www (Sam Goldman in 744af91)\n* flow 0.84 www deploy (Avik Chaudhuri in 59dd225)\n* Bring back the ariaOwneeID prop. (#1883) (Andrea Fercia in ce7f677)\n* Add Node.js version 10 for CI (#1909) (noelyoo in 4a9a6a8)\n* Refactor buffer constructor (#1912) (noelyoo in 11d7379)\n* Update Advanced-Topics-Inline-Styles.md (#1902) (Yao Bin in 0b7ec2a)\n* Remove flow typing for DraftEntity mock (#1891) (Nivedita Chopra in 75aa88a)\n* Flow strict for some files (Nivedita Chopra in bbd3ef1)\n* Update documentation concerning immutable updates (#1884) (Connor Jennings in c336ae2)\n* Update docs to ensure kebab menu shows subheads (#1885) (Connor Jennings in 2ff0c7e)\n* Support npm version 6.x (#1866) (Yangshun Tay in 724fdc6)\n* Remove unused var in BlockTree (#1859) (Nivedita Chopra in 0a45fcd)\n* Update jest version to latest (#1858) (Nivedita Chopra in b962974)\n* Update Advanced-Topics-Entities.md (#1767) (alaoui abdellah in d40ff40)\n* Update link to code of conduct (#1855) (Nivedita Chopra in 8c373b6)\n* var => const on remaining file (Nivedita Chopra in 022798c)\n* Update prettier version to 1.13.6 (#1854) (Nivedita Chopra in e2c24cf)\n* Remove Flow Strict Local from files with future sketchy-null errors after bug fix (George Zahariev in c5b785a)\n* Remove non-leaf blocks in tree => raw conversion (Nivedita Chopra in f5b2acb)\n* Update Docusaurus to 1.3.3 (#1797) (Yangshun Tay in d6a0ac0)\n* modify docs overview url (#1802) (Shubham Tiwari in 9f86efb)\n* v0.79.1 in www (Panagiotis Vekris in 93a90a9)\n* Remove gating on draft_non_native_insertion_forces_selection (Sophie Alpert in 1a5b27a)\n* 5/n Disable forward delete across blocks when nested blocks are enabled (Flarnie Marchan in 0600549)\n* 3/n Splitting PR #1828: updates to the Rich Text Editor example (#1828) (mitermayer in e98e91e)\n* 2/n splitting PR #1828: updating `removeRangeFromContentState` (#1828) (mitermayer in a399e43)\n* 1/n splitting PR #1828: Initial forking of `RichTextEditorUtil` (#1828) (mitermayer in 328ddc6)\n* Warn if `moveSelectionForward/Backward` called with non-collapsed selection (Flarnie Marchan in 99eca6b)\n* codemod jasmine -> jest in html/shared (Aaron Abramov in 7f9299d)\n* Remove logo from background circle (#1800) (Paul O’Shannessy in 47ae65a)\n* var => const on test files (Nivedita Chopra in 0f58b64)\n* Migrate to Docusaurus - Attempt #2 (Noam Elboim in 710919b)\n* Remove old decorator fingerprint logic (Sophie Alpert in b2f6ed0)\n* Use strict-local in as many files as possible (Miorel Palii in 3798902)\n* Pass eventTimeStamp to `handleKeyPress` to allow tracking (Flarnie Marchan in 0ecf9a6)\n* Pass synthetic event to `handleBeforeInput` callback (Flarnie Marchan in b86b5ce)\n* `React.Element<any>` / `React.Element<*>` -> `React.Node` as much as possible (Miorel Palii in a1f4593)\n* Change remaining vars to let/const (Nivedita Chopra in 8de2db9)\n* Removed `@providesModule` tags and dependencies from draft-js (Rubén Norte in ee2e9c8)\n* Add `@providesModule` back to draft-js modules (Ashley Watkins in 05b2b4c)\n* Add common Flow type for decorator components (Ashley Watkins in 8000486)\n* Add `@providesModule` back to draft-js modules (Rubén Norte in 4c4465f)\n* Removed `@providesModule` tag from non-generated files in html/shared directories (1/1) (Rubén Norte in 293f262)\n* 2/n Remove last vestiges of cWU (Flarnie Marchan in e954091)\n* 1/n Move `blockSelect` flag out of cWU (Flarnie Marchan in 0f6199d)\n* Upgrade to Flow v0.68.0 (Sam Goldman in a99f51e)\n* Strict-ify files that can be strict-ified with no additional changes (Miorel Palii in 22f9c52)\n* rename-unsafe-lifecycles (Brian Vaughn in 8b3e8c9)\n* Refactor `convertFromHTMLtoContentBlocks` (Nicolas Champsavoir in 732b69d)\n* Making gkx overwrittable (mitermayer in 7495adf)\n* 2/n Do update `blockSelectEvents` flag, during render (Flarnie Marchan in e571268)\n* 1/n remove GK on `flushSync` (Flarnie Marchan in 4241f43)\n* Playground - Making sure blockMap should always visible by default (mitermayer in 7eb2a50)\n* Move uglifyjs-webpack-plugin to devDependencies (Thibaud Colas in 4de1345)\n* Making a more sane .gitignore (mitermayer in f4bc3a7)\n* Examples cleanup (Ken Hibino in 67f3586)\n* Ensure selection collapses if user tries to replace with matching text (Brian Ng in 084bdb6)\n* Move `_latestEditorState` assignment back to commit phase (Sophie Alpert in 04c2b9c)\n* Remove Node 6 from engines list in package.json (Thibaud Colas in 584d849)\n* Update `_latestEditorState` in render too (Flarnie Marchan in 90a8f22)\n* Widen logging and add stack trace for IE selection bug (Flarnie Marchan in a6317e6)\n* Match block and inline examples for consistency. (cbeninati in e65a8e6)\n* Bundle size stats + Misc changes (Alan Norbauer in 0a1f981)\n* Remove `componentWillUpdate` under GK (Flarnie Marchan in 7885959)\n* try disabling 'blockSelectEvents' flag (Flarnie Marchan in d144883)\n* Update site footer from 2017 -> 2018 (Michael Chen in 558352c)\n* Make the Flow type of `CompositeDraftDecorator`'s constructor more strict (Steven Luscher in a894030)\n* Deprecated the coarse `onArrowUp` et al key handler props on `DraftEditor.react` to make it possible to produce editor commands from these keys (Steven Luscher in dc5ca7f)\n* Wrap Draft handlers in `flushControlled` instead of `flushSync` (Andrew Clark in cda13cb)\n* Update docs/APIReference-Editor.md (Sai Kishore Komanduri in 27a5f10)\n* Bumping internal flow version (mitermayer in 342a51a)\n* Switch from `DraftFeatureFlags` to gkx() (Sophie Alpert in 07eb9c4)\n* Add `flushSync` to Draft.js for *only* GK folks (Flarnie Marchan in 26040e5)\n\n### Fixed\n* Fixed drag and drop `.length` error (#2117) (job in 2487e7d)\n* Fix broken id anchor (#2095) (Sajad Torkamani in eddcc55)\n* Typo corrected - Overview.md (#2089) (Jonathan Erlich in 87a812d)\n* fix: set to nested list items to right depth (Kevin Li in 12c4480)\n* fix(styles): avoid permanently accumulating attribute styles (Kevin Li in 7cfb055)\n* Fixes runtime error when cutting empty selection at the end of the content (Claudio Procida in 23fc70f)\n* Fixing major Android editing issues (#2035) (Fabio M. Costa in 634bd29)\n* Fix broken link in Overview.md (#2062) (seojeee in e8e0bcf)\n* Fix failing `DraftStringKey` test (#2064) (Claudio Procida in fe4e266)\n* Fixes require order lint issues /2 (Claudio Procida in 76e121e)\n* Fixes require order lint issues (Claudio Procida in e2c5357)\n* Fix the issue of draft JS does not do copy and paste correctly with custom entities. (Tee Xie in d09ef3e)\n* fix typo in README.md (#2055) (Tanner Eustice in 75a89ff)\n* rename `*.test.js` to `*-test.js` to match naming convention (Aaron Abramov in dc58df8)\n* Convert some of draftjs' `ReactDOM.findDOMNode` to refs (#2051) (Dennis Wilkins in 1fae34f)\n* Correct warning condition (#2049) (Ben Gardner in ffd8f59)\n* Fix npm run dev (#2030) (Fabio M. Costa in 3c01ef6)\n* Specify correct type of `joinClasses` (George Zahariev in 7b9a7e1)\n* Restores flow error suppression for fbjs@1.0.0 (#2014) (Claudio Procida in 6a26a82)\n* Fix leading line feed conversion (Guillaume Aubert in 5081c87)\n* Handles `<br>` tags in refactored HTML converter (Claudio Procida in fdf63aa)\n* Typo fix in code comment (#1997) (Deniz Susman in e84e757)\n* Fix bad destructuring when content block key has a `-` (#1995) (Jan Karlo Dela Cruz in c21a9f7)\n* Fix typo in code comment for DraftEditor (#1991) (Deniz Susman in 7167210)\n* Fixes lint warnings in `convertFromHTMLToContentBlocks2` tests (Claudio Procida in e942ee9)\n* Update fbjs to 1.0.0 to fix ReDos Vulnerability (#1978) (Anthony Muscat in 9b2a366)\n* Normalize copyright headers to BSD + patents grant and drop the year (#1964) (Claudio Procida in 642aa11)\n* Fixes flow error (#1962) (Claudio Procida in fb7882b)\n* Remove unused suppression comments from www as of v0.89 (Gabe Levi in 8dd6dda)\n* Add correct type annotations to DraftEditor.react.js (Paco Estevez Garcia in 83edf02)\n* Fix `$FlowFixMe` type not working for CI builds of draft-js (Paco Estevez Garcia in 81f92ee)\n* Annotate exports codemod on html/shared (Paco Estevez Garcia in 7cb10f9)\n* Revert D13097194: [codemod][types-first] Add type annotations to html/shared (Craig Phillips in 010fce7)\n* Add type annotations to html/shared (Paco Estevez Garcia in 6f4102d)\n* Fix all 'curly' violations (Paul O'Shannessy in ab199ef)\n* Fix tex and universal examples crash because of different React versions (#1756) (#1931) (Thibaud Colas in 7dddded)\n* Fix typo (#1913) (noelyoo in 1d3c77f)\n* Fixes some drag-n-drop problems (#1599) (Denis Oblogin in 20a0f73)\n* Bug/1668 (#1691) (Alexis H in 1d2d854)\n* Fix SelectionState’s `hasEdgeWithin` (#1811) (Andrew Branch in 7666e95)\n* Fix drop issue (#1725) (LaySent in 800d6b5)\n* fixes #868 (#1878) (Julian Krispel in 6ba124c)\n* Fix check for tree blocks (Nivedita Chopra in 690f7ef)\n* Fix bug in merge blocks (Nivedita Chopra in 7daa87e)\n* Fix raw to tree conversion (Nivedita Chopra in 8ac1922)\n* Bug Fix - Remove deleted block from its parent's children (Nivedita Chopra in 02e0e00)\n* Fix small typo (#1865) (Valentin Hervieu in 8bb9c6c)\n* Fix paste handling for images with `role=\"presentation\"` (Jainil Parekh in 6df3808)\n* Minor fix in entities docs (#1534) (Alastair Hole in 9f0d115)\n* Fixes incorrect docs, see #1497 (#1837) (Matt Greenfield in a18b6fe)\n* Fixes warning for missing keys in example color controls (#1853) (Claudio Procida in 4a5ad07)\n* Fix Lint errors for type imports (Nivedita Chopra in e6c693c)\n* Fix Travis breakage caused due to unimported `idx` module (Nivedita Chopra in 3306ddf)\n* Fix `DraftTreeAdapter` to respect the tree invariants (Nivedita Chopra in 39be488)\n* Inline call to `gkx` to combat fatal in `ContentState` (Steven Luscher in a6c9ffd)\n* Handle ReactDOM type errors (Ashley Watkins in 9130859)\n* Fix tree invariants test (#1836) (Nivedita Chopra in 05208a8)\n* Fix unlucky failures in character replacement (Sophie Alpert in ae25b8f)\n* Regression test for bug with nested block and deleting (Flarnie Marchan in 2d7ad18)\n* Tree Data - Fix for backspace at the start of a nested block (Nivedita Chopra in cf48f77)\n* Tree Data - Don't update pointers if range is within the same block (Nivedita Chopra in f3d3490)\n* Fix Draft input cursor jumping to the end (Dan Abramov in 37dadd3)\n* Fix tests to be independent on the implementation of invariant (Matthew McKeen in 81cc54b)\n* Re-apply order-requires linter on html/shared/ (Dave Alongi in 0bb8d76)\n* Auto-fix `prefer-const` ESLint rule (3/n) (Miorel Palii in bf1a028)\n* Auto-fix all auto-fixable eqeqeq problems (Miorel Palii in eea70f4)\n* Fixing Docusaurus migration issues (Noam Elboim in 72ad814)\n* Fix block tree before/after comparison (Sophie Alpert in fa88ee1)\n* Fixed license, Flow and lint issues in draft-js (Rubén Norte in 3e9ff8e)\n* Actually for real fix the flow type of decorator props (Flarnie Marchan in 7e1a107)\n* Workaround for BlockNode variance issue caused by flow transform (#1621) (Bob Ippolito in 1d77500)\n* Revert \"rename-unsafe-lifecycles\" (mitermayer in 6eec8f9)\n* Fix typo (Aditya Bhardwaj in 6ef6c66)\n* Website: Fixed code highlight (Marcelo Jorge Vieira in 04c667c)\n* Fixing tex example (Guilherme Miranda in 900ef76)\n* Fix typo (Thomas Broadley in 35b3605)\n* Fixing master (mitermayer in 4c12ead)\n* Fix Linux keyboard shortcuts (Thomas Nardone in f6fbf1c)\n* fix typo in changelog (Flarnie Marchan in 93bc209)\n\n### Meta\n* Add issue triage guidelines to CONTRIBUTING.md (#1896) (Nivedita Chopra in 7df9eb9)\n* Add meeting notes for 10/12 (#1901) (Nivedita Chopra in 9a96ab0)\n* Add meeting notes from 9/7 (#1862) (Nivedita Chopra in b8ea228)\n* Change oncall to draft_js (Nivedita Chopra in fbc8a0c)\n* Update biweekly sync meeting notes from February 2018 (Flarnie Marchan in 1ef4044)\n* Update weekly meeting notes from Oct. 2017 - Jan. 2018 (Flarnie Marchan in 7017825)\n\n\n## 0.10.5 (January 19th, 2018)\n\n### Added\n* Add support for `ariaDescribedBy` prop, for better a11y. (Suraj Karnati in\n  [a6af3e15](https://github.com/facebook/draft-js/commit/a6af3e15120e74c8797c5670f5bb63cb45c49a32))\n* Add support for `ariaLabelledBy` prop, for better a11y. ([@jackyho112](https://github.com/jackyho112)\n  in [#1519](https://github.com/facebook/draft-js/pull/1519))\n\n### Changed\n* Cause editor to break out of code block when user enters two blank lines. (Hanzhi Zhang\n  in [548fd5d1](https://github.com/facebook/draft-js/commit/548fd5d1b1c31b7b4c79cd70b101fae69d522b3f))\n\n### Fixed\n* Preserve list indentation when copying and pasting from one Draft.js editor\n  into another. ([@GordyD](https://github.com/GordyD) in [#1605](https://github.com/facebook/draft-js/pull/1605))\n* Fix `cannot read property 'update' of undefined` error that was thrown when\n  typing same character into selection that starts with that character. ([@existentialism](https://github.com/existentialism) in\n  [#1512](https://github.com/facebook/draft-js/pull/1512))\n* Fix `encodeRawBlocks` to handle non-contiguous entities. Entities should\n  always be contiguous, and cover one sequential range of characters. However,\n  in cases where entityState is corrupted to include non-contiguous entities,\n  `encodeRawBlocks` would improperly process the entities in that case. (Frank\n  Thompson in [0059dd46](https://github.com/facebook/draft-js/commit/0059dd46f4d23af7d9803316aa93d8deddb5e8ae))\n* Updated CSS for DraftEditorPlaceholder to support multiline placeholder (Gaurav Vaish in\n  [c38b0285](https://github.com/facebook/draft-js/commit/c38b028513214416d66a3fdf191745dfde04ed2b)\n* Fix issue where typing at the end of a link caused the link to continue. (Ian\n  Jones in\n  [d16833b3](https://github.com/facebook/draft-js/commit/d16833b3dae77ccf13e3af7f5e42c8131b0d1d2c))\n* Fix regression of bug where clicking a link caused the focus to move but the\nselection state was not cleared, leading to a 'node not found' error.\n  ([@flarnie](https://github.com/flarnie)\n  in [55316176](https://github.com/facebook/draft-js/commit/553161761903bed7fad971d73e1fe04bb0ff360e))\n* Loosen Flow type definition for DraftBlockType to allow user-defined custom\n  block types. ([@mitermayer](https://github.com/mitermayer)\n  in [#1480](https://github.com/facebook/draft-js/pull/1480))\n\n## 0.10.4 (October 24th, 2017)\n\n### Added\n* Expose `onRightArrow` and `onLeftArrow` props to allow handling keyboard\n  events when right or left arrow is pressed.\n  ([@eessex](https://github.com/eessex)\n  in [#1384](https://github.com/facebook/draft-js/pull/1384))\n* Expose Draft.css as default CSS export in package.json for use by CSS\n  preprocessors. ([@darobin](https://github.com/darobin )\n  in [#566](https://github.com/facebook/draft-js/pull/566))\n\n### Changed\n* Change 'lookUpwardForInlineStyle' from O(n^2) to O(n), improving performance.\n  :) ([@Lemmih](https://github.com/Lemmih)\n  in [#1429](https://github.com/facebook/draft-js/pull/1429))\n\n### Fixed\n* Fix bug where editors inside draggable parent were broken for Safari.\n  ([@mattkrick](https://github.com/mattkrick) in\n  [#1326](https://github.com/facebook/draft-js/pull/1326))\n* Stop pulling in Enzyme as production dependency. D'oh.\n  ([@flarnie](https://github.com/flarnie) in\n  [#1415](https://github.com/facebook/draft-js/pull/1415))\n* Fix `TypeError: Cannot read property 'nodeType' of undefined` error where\n  `anchorNode` was `undefined`.\n  ([@tleunen](https://github.com/tleunen) in\n  [#1407](https://github.com/facebook/draft-js/pull/1407))\n* Fix error thrown when callback tries to `focus` on editor after it has been\n  unmounted.  ([@mattkrick](https://github.com/mattkrick) in\n  [#1409](https://github.com/facebook/draft-js/pull/1409))\n* Fix bug where selecting a single character then typing it doesn't replace it.\n  ([@karanjthakkar](https://github.com/karanjthakkar) in\n  [#719](https://github.com/facebook/draft-js/pull/719))\n* Clear the block type when backspacing at the start of the first block with\n  rich text utils.  ([@jvaill](https://github.com/jvaill) in\n  [#748](https://github.com/facebook/draft-js/pull/748))\n\n## 0.10.3 (September 28th, 2017)\n\n### Added\n* Allow React 16.\\* as peer dependency. ([@nikgraf](https://github.com/nikgraf)\n  in [#1385](https://github.com/facebook/draft-js/pull/1385))\n\n### Fixed\n* Fixed bug where using a custom block type without overriding the default block\n  map threw an error. ([@southerncross](https://github.com/southerncross) in\n  [#1302](https://github.com/facebook/draft-js/pull/1302))\n* Update dependency on `fbjs` to get fix for bug where `focus()` caused\n  unexpected scroll ([@flarnie](https://github.com/flarnie) in\n  [#1401](https://github.com/facebook/draft-js/pull/1401))\n\n## 0.10.2\n\n### Added\n* Added support for `aria-controls` in draft.js ([@jessebeach](https://github.com/jessebeach) in [7f0cab28](https://github.com/facebook/draft-js/commit/7f0cab28386ec4bde8ec6289377bff9e53cd019b))\n\n### Changed\n* Change `aria-owns` to `aria-controls` in draft.js. ([@jessebeach](https://github.com/jessebeach) in [7f0cab28](https://github.com/facebook/draft-js/commit/7f0cab28386ec4bde8ec6289377bff9e53cd019b))\n  * Deprecates support of `ariaOwns` and `ariaOwneeID` props.\n* Deprecate use of `ariaHasPopup` prop in draft.js. `ariaExpanded` should be used instead if an input is showing a dropdown with options.([@jessebeach](https://github.com/jessebeach) in [744e9b4e](https://github.com/facebook/draft-js/commit/744e9b4eb4810797a93c66591fea6f9cac533b4b))\n* Pasting an `img` no longer inserts the `src` by default; now inserts image emoji if no decorator is used. ([@aadsm](https://github.com/aadsm) in [0b22d713](https://github.com/facebook/draft-js/commit/0b22d713d556ccc4820850099ad6231493b3f7aa) and [@flarnie](https://github.com/flarnie) in [1378](https://github.com/facebook/draft-js/pull/1378))\n\n### Fixed\n\n* Fix issue where selection state was not cleared on blur and refocus of the\n  editor. ([@sophiebits](https://github.com/sophiebits) in\n  [19b9b1c5](https://github.com/facebook/draft-js/commit/19b9b1c5007bcb3a4111ea31f8d9a8cda629a1ff))\n* Fix issue where pasting code into code block defaulted to plain text, and\n  styles were dropped from pasted blocks in general.\n  ([@bumbu](https://github.com/bumbu) in\n  [e8d10112](https://github.com/facebook/draft-js/commit/e8d101121fb9dd9203a46d899124a7be4b0b2936))\n* Fix issue where Flow was not running with some 'import' statements ([@flarnie](https://github.com/flarnie) & [@yuku-t](https://github.com/yuku-t) in [#1263](https://github.com/facebook/draft-js/pull/1262))\n* Fix bug where Draft threw when two keys were pressed at same time in React 16 async mode ([@sophiebits](https://github.com/sophiebits) in [1c6a49b8](https://github.com/facebook/draft-js/commit/1c6a49b8801183fe0c29458626c0b5dbe1238e59))\n* Fix recent Chrome bug where tab causes error ([@sophiebits](https://github.com/sophiebits) in [5863399a](https://github.com/facebook/draft-js/commit/5863399a3a1bcbbe9b090249504a70496a7af7cc))\n* Fix \"Refs must have owner\" error when multiple copies of React are used ([@mks11](https://github.com/mks11) in [#925](https://github.com/facebook/draft-js/pull/925))\n* Fix issue where AT could treat 'return' as submit in Draft ([@jessebeach](https://github.com/jessebeach) in [#1295](https://github.com/facebook/draft-js/pull/1295))\n* Don't allow `aria-expanded` to be true unless the aria role is combobox ([@jessebeach](https://github.com/jessebeach) in [3494d45d](https://github.com/facebook/draft-js/commit/3494d45d32b64d6e82e4b3e8fcade6a2b5c6bd46))\n* Fix pesky \"This Selection object doesn't have any Ranges\" bug ([@sophiebits](https://github.com/sophiebits) in [96688e10](https://github.com/facebook/draft-js/commit/96688e10b22a778c76e03009da4b9f3d05eba5f7) and [036e3a84](https://github.com/facebook/draft-js/commit/036e3a848e3593c97f4c3011e1ddc045e128a7af))\n* Fix bug where pasting `img` with large data URL source could crash editor ([@aadsm](https://github.com/aadsm) in [0b22d713](https://github.com/facebook/draft-js/commit/0b22d713d556ccc4820850099ad6231493b3f7aa))\n\n## 0.10.1\n\n### Added\n\n* Support UMD in dist output format (#1090)\n* Expose textDirectionality prop\n* Expose props disabling auto-correct, auto-complete, auto-capitalize\n* Add `editorKey` prop for SSR\n* Pass `block` to `customStyleFn` callback\n* Added `moveAtomicBlock` to `AtomicBlockUtils`\n\n### Fixed\n\n* Fix some cases of \"Failed to execute 'setStart' on 'Range\" bug (#1162)\n* Fix Chrome text deletion bug (#1155)\n* Pass fresh editorState to edit handlers (#1112 and #1113)\n* Fix for text insertion bugs in Android 5.1\n* Correctly delete immutable and segmented entity content when at the edge of a\n  selection\n  * Fix bug where all text except first letter was dropped in IE11\n  * Fix bug where starting new line incorrectly toggled inline style\n  * Fix 'getRangeClientRects' to work around [webkit selection bounding rect\n    bug](https://www.youtube.com/watch?v=TpNzVH5jlcU)\n\n## 0.10.0 (Dec. 16, 2016)\n\n### Added\n\n* Add improved API for entity manipulation to contentState\n* Add deprecation warnings to old Entity module API\n* Add image support to convertFromHTML\n* Add option of 'aliasedElements' in block render map\n\n### Changed\n\n* This version supports both the old and new Entity API; we\n  are deprecating the Entity module in favor of\n  using contentState. See [the migration guide.](https://draftjs.org/docs/v0-10-api-migration.html#content)\n\n### Fixed\n\n* Fix bug where block data was not removed when deleting atomic block\n* Fix bug preventing pasting from clipboard\n* Fix dead key deletion and deletion in 2-Set Korean\n* Fix ContentState.createFromBlockArray to allow taking an empty array\n* Improve typing in Korean on Windows\n\n## 0.9.1 (September 16, 2016)\n\n### Added\n\n* `customStyleFn` for more control over inline style ranges\n\n### Fixed\n\n* Update Flow version\n* Fix flow error in DraftEditorDragHandler\n\n## 0.9.0 (September 13, 2016)\n\n### Changed\n\n* Return 'handled' or 'not-handled' from cancellable handlers callback\n  * Boolean return value is deprecated\n* Expand and update documentation\n\n### Fixed\n\n* Fix selection of atomic block when it is the last block\n* Preserve the depth of custom block types when converting to raw\n* Stop mutating component children when creating blocks with wrapper elements\n\n## 0.8.1 (August 12, 2016)\n\n### Fixed\n\n* Include `object-assign` in npm dependencies\n* Include `babel-core` in npm dependencies of tex example\n\n## 0.8.0 (August 8, 2016)\n\n### Added\n\n* `customStyleFn` for more control over inline style ranges\n* Uses `internalClipboard` for Safari\n* Metadata for `ContentBlock` objects\n* `convertFromHTMLToContentBlocks`:\n  * Support for `mailto` protocol for links\n  * Support \"unset\" inline styles\n* Run ESLint on examples\n\n\n### Changed\n\n* Removed redundant ESLint module in TeX example\n* Update Travis CI config for readability, Node v4 requirements, and pruning/updating npm dependencies\n* Use `immutable` ~3.7.4 to avoid Flow errors in updated versions\n* Modify `getSelectionOffsetKeyForNode` to search for nested offset-annotated nodes\n* Upgrade eslint to 3.0.1, use fbjs config\n* Update to Flow 0.28\n* Jest\n  * Update to 12.1.1\n  * Replaced `jest.fn().mockReturnValue(x)` with `jest.fn(() => x)`\n* Remove extra spaces from the text decoration style\n* No longer using `nullthrows` for `blockRenderMap`\n* `convertFromHTMLToContentBlocks`:\n  * Improved variable names in `joinChunks`\n  * Additional whitelisted entities such as `className`, `rel`, `target`, `title`\n\n### Fixed\n\n* Fix bug where placeholder text was not being erased in Chrome\n* Fix bug where double click link in Firefox broke selection\n* Kill iOS tooltips\n* removed unnecessary `undefined` checks on `DraftEditorLeaf`\n* `convertFromHTMLToContentBlocks`:\n  * Preserve pasted block type on paste\n  * Strip XML carriage returns and zero-width spaces\n  * `getBlockMapSupportedTags()` will always return a valid array of tags\n* Documentation fixes\n\n## 0.7.0 (May 3, 2016)\n\n### Added\n\n* `blockRenderMap`: A map that allows configuration for the DOM elements and\nwrapper components to render, keyed by block type\n  * Includes configurability of element-to-block-type paste processing\n\n### Changed\n\n* Update to Jest 11.0.2\n\n### Fixed\n\n* Change deletion behavior around `atomic` blocks to avoid DOM selection errors\n* Properly apply entities across multiple blocks in\n* Improve placeholder behavior for a11y\n* Properly remove and modify entity ranges during spellcheck changes\n* Match Chrome `<textarea>` behavior during <kbd>cmd</kbd>+<kbd>backspace</kbd>\ncommand at visual line-start\n\n## 0.6.0 (April 27, 2016)\n\n### Added\n\n* `ContentState.getFirstBlock()` convenience method\n\n### Changed\n\n* <kbd>return</kbd> key handling now goes through command flow to enable easier\ncustom `'split-block'` handling.\n* `convertFromRaw` now returns a `ContentState` object instead of an\n`Array<ContentBlock>`\n\n## 0.5.0 (April 12, 2016)\n\n### Fixed\n\n* <kbd>option</kbd>+<kbd>spacebar</kbd> no longer incorrectly scrolls browser in Chrome OSX\n* Cursor behavior when adding soft newlines\n\n### Added\n\n* `AtomicBlockUtils`, a utility module to simplify adding `atomic` blocks to\nan `EditorState`\n\n### Changed\n\n* The `media` block type is now `atomic`, to better represent that this type\nis not just intended for photos and videos\n\n## 0.4.0 (April 6, 2016)\n\n### Fixed\n\n* Avoid clearing inline style override when setting block type or depth\n\n### Added\n\n* `editable` field for custom block component configuration\n* Default key binding support for <kbd>Ctrl</kbd>+<kbd>M</kbd> (`split-block`)\n\n### Changed\n\n* Always wrap custom block components, based on block type\n  * Includes `data-editor`, `data-offset-key`, `data-block` in block props\n* Replace `onPasteRawText` prop with `handlePastedText`\n\n## 0.3.0 (March 22, 2016)\n\n### Fixed\n\n* Properly extract custom inline styles for `convertToRaw`\n* Fix internal paste behavior to better handle copied custom blocks\n\n### Added\n\n* Export `getVisibleSelectionRect`\n* Export `convertFromHTML`\n* Export `DraftEditorBlock`\n\n## 0.2.2 (March 9, 2016)\n\n### Fixed\n\n* Build before publish to get the warning suppression in place correctly\n\n## 0.2.1 (March 9, 2016)\n\n### Added\n\n* React 15 RC as peer/dev dependency, provide `suppressContentEditableWarning`\n\n## 0.2.0 (March 8, 2016)\n\n### Added\n\n* Move `white-space: pre-wrap` into inline style to resolve insertion issues\n* `handleDrop` prop method for `Editor` to allow manual drop management\n* `decoratedText` prop for decorator components\n* `getVisibleSelectionRect`, to provide Rect for DOM selection\n* Export `KeyBindingUtil` and `getDefaultKeyBinding`\n\n### Fixed\n\n* Triple-clicks followed by block type changes now only affect first block\n* `DraftEditorLeaf` now re-renders correctly when its styles change\n* Backspace behavior within empty code blocks\n\n## 0.1.0 (February 22, 2016)\n\n* Initial public release\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to make participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\n  advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies within all project spaces, and it also applies when\nan individual is representing the project or its community in public spaces.\nExamples of representing a project or community include using an official\nproject e-mail address, posting via an official social media account, or acting\nas an appointed representative at an online or offline event. Representation of\na project may be further defined and clarified by project maintainers.\n\nThis Code of Conduct also applies outside the project spaces when there is a\nreasonable belief that an individual's behavior may have a negative impact on\nthe project or its community.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at <opensource-conduct@fb.com>. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to Draft.js\nWe want to make contributing to this project as approachable and transparent as\npossible.\n\n## Code of Conduct\nFacebook has adopted a Code of Conduct that we expect project\nparticipants to adhere to. Please [read the full text](https://code.facebook.com/codeofconduct)\nso that you can understand what actions will and will not be tolerated.\n\n## Our Development Process\nWe use GitHub to sync code to and from our internal repository. We'll use GitHub\nto track issues and feature requests, as well as accept pull requests.\n\n## Pull Requests\nWe actively welcome your pull requests.\n\n1. Fork the repo and create your branch from `master`.\n2. If you've added code that should be tested, add tests.\n3. If you've changed APIs, update the documentation.\n4. Ensure the test suite passes.\n5. Make sure your code lints.\n6. If you haven't already, complete the Contributor License Agreement (\"CLA\").\n\n## Contributor License Agreement (\"CLA\")\nIn order to accept your pull request, we need you to submit a CLA. You only need\nto do this once to work on any of Facebook's open source projects.\n\nComplete your CLA here: <https://code.facebook.com/cla>\n\n## Coding Style  \n* 2 spaces for indentation rather than tabs\n* 80 character line length\n* Run `npm run lint` to conform to our lint rules\n\n## Issues\nWe use GitHub issues to track public bugs. Please ensure your description is\nclear and has sufficient instructions to be able to reproduce the issue.\nIf possible please provide a minimal demo of the problem. You can use this\njsfiddle to get started: https://jsfiddle.net/gmertk/e61z7nfa/.\n\nFacebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe\ndisclosure of security bugs. In those cases, please go through the process\noutlined on that page and do not file a public issue.\n\n## Issue Triage\nHere are some tags that we're using to better organize issues in this repo:\n\n* `good first issue` - Good candidates for someone new to the project to contribute.\n* `help wanted` - Issues that should be addressed and which we would welcome a\nPR for but may need significant investigation or work\n* `support` - Request for help with a concept or piece of code but this isn't an\nissue with the project.\n* `needs more info` - Missing repro steps or context for both project issues \\&\nsupport questions.\n* `discussion` - Issues where folks are discussing various approaches \\& ideas.\n* `question` - Something that is a question specifically for the maintainers such\nas [this issue about the license](https://github.com/facebook/draft-js/issues/1819).\n* `documentation` - Relating to improving documentation for the project.\n- Browser \\& OS-specific tags for anything that is specific to a particular\nenvironment (e.g. `chrome`, `firefox`, `macos`, `android` and so forth).\n\n## Stability\nOur philosophy regarding API changes is as follows:\n * We will avoid changing APIs and core behaviors in general\n * In order to avoid stagnation we will allow for API changes in cases where\n there is no other way to achieve a high priority bug fix or improvement.\n * When there is an API change:\n    * Changes will have a well documented reason and migration path\n    * When deprecating a pattern, these steps will be followed:\n        * We will test the change internally first at FB\n        * A version will be released that supports both, with deprecation warnings\n        * The following version will fully remove the deprecated pattern\n\n## License\nBy contributing to Draft.js, you agree that your contributions will be licensed\nunder its MIT license.\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) Facebook, Inc. and its affiliates.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "LICENSE-examples",
    "content": "Copyright (c) 2013-present, Facebook, Inc. All rights reserved.\n\nThe examples provided by Facebook are for non-commercial testing and evaluation\npurposes only. Facebook reserves all rights not expressly granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\nFACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://draftjs.org/\">\n    <img src=\"https://draftjs.org/img/draftjs-logo.svg\" alt=\"draftjs-logo\" width=\"8%\" />\n  </a>\n</p>\n<h1 align=\"center\">\n  Draft.js\n</h1>\n<p align=\"center\">\n  <a href=\"https://travis-ci.org/facebook/draft-js\">\n    <img src=\"https://img.shields.io/travis/facebook/draft-js/master.svg?style=flat\" alt=\"Build Status\" />\n  </a>\n  <a href=\"https://yarn.pm/draft-js\">\n    <img src=\"https://img.shields.io/npm/v/draft-js.svg?style=flat\" alt=\"npm version\" />\n  </a>\n</p>\n<p align=\"center\">\n  <img src=\"https://media.giphy.com/media/XHUjaxELpc11SiRSqN/giphy.gif\" alt=\"Live Demo\" />\n</p>\n\n--------------------\n## Status\n\n**THIS PROJECT IS CURRENTLY IN MAINTENANCE MODE. It will not receive any feature updates, only critical security bug patches. On 31st December 2022 the repo will be fully archived.**\n\nFor users looking for an open source alternative, Meta have been working on migrating to a new framework, called [Lexical](https://github.com/facebook/lexical). It's still experimental, and we're working on adding migration guides, but, we believe, it provides a more performant and accessible alternative.\n\n--------------------\nDraft.js is a JavaScript rich text editor framework, built for React and\nbacked by an immutable model.\n\n- **Extensible and Customizable:** We provide the building blocks to enable\nthe creation of a broad variety of rich text composition experiences, from\nbasic text styles to embedded media.\n- **Declarative Rich Text:** Draft.js fits seamlessly into\n[React](http://facebook.github.io/react/) applications,\nabstracting away the details of rendering, selection, and input behavior with a\nfamiliar declarative API.\n- **Immutable Editor State:** The Draft.js model is built\nwith [immutable-js](https://facebook.github.io/immutable-js/), offering\nan API with functional state updates and aggressively leveraging data persistence\nfor scalable memory usage.\n\n[Learn how to use Draft.js in your own project.](https://draftjs.org/docs/getting-started/)\n\nDraft.js is used in production on Facebook, including status and\ncomment inputs, [Notes](https://www.facebook.com/notes/), and\n[messenger.com](https://www.messenger.com).\n\n## API Notice\n\nBefore getting started, please be aware that we recently changed the API of\nEntity storage in Draft. \n\nPreviously, the old API was set to be removed in `v0.11.0`. Since, the plans have changed— `v0.11.0` still supports the old API and `v0.12.0` will remove it. Refer to [the docs](https://draftjs.org/docs/v0-10-api-migration) for more information and information on how to migrate.\n\n## Getting Started\n\n```\nnpm install --save draft-js react react-dom\n\nor\n\nyarn add draft-js react react-dom\n```\n\nDraft.js depends on React and React DOM which must also be installed.\n\n### Using Draft.js\n\n```javascript\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport {Editor, EditorState} from 'draft-js';\n\nfunction MyEditor() {\n\n  \n  constructor(props) {\n    super(props);\n    this.state = {editorState: EditorState.createEmpty()};\n    this.onChange = (editorState) => this.setState({editorState});\n    this.setEditor = (editor) => {\n      this.editor = editor;\n    };\n    this.focusEditor = () => {\n      if (this.editor) {\n        this.editor.focus();\n      }\n    };\n  }\n\n  componentDidMount() {\n    this.focusEditor();\n  }\n\n  render() {\n    return (\n      <div style={styles.editor} onClick={this.focusEditor}>\n        <Editor\n          ref={this.setEditor}\n          editorState={this.state.editorState}\n          onChange={this.onChange}\n        />\n      </div>\n    );\n  }\n}\n\nconst styles = {\n  editor: {\n    border: '1px solid gray',\n    minHeight: '6em'\n  }\n};\n\nReactDOM.render(\n  <MyEditor />,\n  document.getElementById('container')\n);\n```\n\nSince the release of React 16.8, you can use [Hooks](https://reactjs.org/docs/hooks-intro.html) as a way to work with `EditorState` without using a class.\n\n\n```js\nimport React from \"react\";\nimport { Editor, EditorState } from \"draft-js\";\nimport \"draft-js/dist/Draft.css\";\n\nexport default function MyEditor() {\n  const [editorState, setEditorState] = React.useState(() =>\n    EditorState.createEmpty()\n  );\n\n  const editor = React.useRef(null);\n  function focusEditor() {\n    editor.current.focus();\n  }\n\n  return (\n    <div\n      style={{ border: \"1px solid black\", minHeight: \"6em\", cursor: \"text\" }}\n      onClick={focusEditor}\n    >\n      <Editor\n        ref={editor}\n        editorState={editorState}\n        onChange={setEditorState}\n        placeholder=\"Write something!\"\n      />\n    </div>\n  );\n}\n\n```\n\nNote that the editor itself is only as tall as its contents. In order to give users a visual cue, we recommend setting a border and a minimum height via the `.DraftEditor-root` CSS selector, or using a wrapper div like in the above example.\n\nBecause Draft.js supports unicode, you must have the following meta tag in the `<head>` `</head>` block of your HTML file:\n\n```html\n<meta charset=\"utf-8\" />\n```\n\nFurther examples of how Draft.js can be used are provided in the `/examples` directory of this repo.\n\n### Building Draft.js\n\nDraft.js is built with [Yarn](https://classic.yarnpkg.com/en/) v1. Using other package managers mgiht work, but is not officially supported.\n\nTo clone and build, run:\n\n```\ngit clone https://github.com/facebook/draft-js.git\ncd draft-js\nyarn install\nyarn run build\n```\n\n### Examples\n\nTo run the examples in the `/examples` directory, first build Draft.js locally as described above. Then, open the example HTML files in your browser.\n\n## Browser Support\n\n| ![IE / Edge](https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_32x32.png) <br /> IE / Edge | ![Firefox](https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_32x32.png) <br /> Firefox | ![Chrome](https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_32x32.png) <br /> Chrome | ![Safari](https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_32x32.png) <br /> Safari | ![iOS Safari](https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari-ios/safari-ios_32x32.png) <br />iOS Safari | ![Chrome for Android](https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_32x32.png) <br/> Chrome for Android |\n| --------- | --------- | --------- | --------- | --------- | --------- |\n| IE11, Edge [1, 2]| last 2 versions| last 2 versions| last 2 versions| not fully supported [3] | not fully supported [3]\n\n[1] May need a shim or a polyfill for some syntax used in Draft.js ([docs](https://draftjs.org/docs/advanced-topics-issues-and-pitfalls/#polyfills)).\n\n[2] IME inputs have known issues in these browsers, especially Korean ([docs](https://draftjs.org/docs/advanced-topics-issues-and-pitfalls/#ime-and-internet-explorer)).\n\n[3] There are known issues with mobile browsers, especially on Android ([docs](https://draftjs.org/docs/advanced-topics-issues-and-pitfalls/#mobile-not-yet-supported)).\n\n## Resources and Ecosystem\n\nCheck out this curated list of articles and open-sourced projects/utilities: [Awesome Draft-JS](https://github.com/nikgraf/awesome-draft-js).\n\n## Discussion and Support\n\nJoin our [Slack team](https://draftjs.herokuapp.com)!\n\n## Contribute\n\nWe welcome pull requests. Learn how to\n[contribute](https://github.com/facebook/draft-js/blob/master/CONTRIBUTING.md).\n\n## License\n\nDraft.js is [MIT licensed](https://github.com/facebook/draft-js/blob/master/LICENSE).\n\nExamples provided in this repository and in the documentation are separately\nlicensed.\n"
  },
  {
    "path": "docs/APIReference-APIMigration.md",
    "content": "---\nid: v0-10-api-migration\ntitle: v0.10 API Migration\n---\n\nThe Draft.js v0.10 release includes a change to the API for managing\n`DraftEntity` data; the global 'DraftEntity' module is being deprecated and\n`DraftEntity` instances will be managed as part of `ContentState`. This means\nthat the methods which were previously accessed on `DraftEntity` are now moved\nto the `ContentState` record.\n\nThe old API was set to be permanently removed in v0.11, but will now be removed in v0.12. Make sure to migrate over!\n\nThis API improvement unlocks the path for many benefits that will be available in v0.12:\n\n- DraftEntity instances and storage will be immutable.\n- DraftEntity will no longer be globally accessible.\n- Any changes to entity data will trigger a re-render.\n\n## Quick Overview\n\nHere is a quick list of what has been changed and how to update your application:\n\n### Creating an Entity\n\n**Old Syntax**\n\n```js\nconst entityKey = Entity.create(urlType, 'IMMUTABLE', {src: urlValue});\n```\n\n**New Syntax**\n\n```js\nconst contentStateWithEntity = contentState.createEntity(urlType, 'IMMUTABLE', {\n  src: urlValue,\n});\nconst entityKey = contentStateWithEntity.getLastCreatedEntityKey();\n```\n\n### Getting an Entity\n\n**Old Syntax**\n\n```js\nconst entityInstance = Entity.get(entityKey);\n// entityKey is a string key associated with that entity when it was created\n```\n\n**New Syntax**\n\n```js\nconst entityInstance = contentState.getEntity(entityKey);\n// entityKey is a string key associated with that entity when it was created\n```\n\n### Decorator strategy arguments change\n\n**Old Syntax**\n\n```js\nconst compositeDecorator = new CompositeDecorator([\n  {\n    strategy: (contentBlock, callback) =>\n      exampleFindTextRange(contentBlock, callback),\n    component: ExampleTokenComponent,\n  },\n]);\n```\n\n**New Syntax**\n\n```js\nconst compositeDecorator = new CompositeDecorator([\n  {\n    strategy: (contentBlock, callback, contentState) => (\n      contentBlock, callback, contentState\n    ),\n    component: ExampleTokenComponent,\n  },\n]);\n```\n\nNote that ExampleTokenComponent will receive contentState as a prop.\n\nWhy does the 'contentState' get passed into the decorator strategy now? Because we may need it if our strategy is to find certain entities in the contentBlock:\n\n```js\nconst mutableEntityStrategy = function(contentBlock, callback, contentState) {\n  contentBlock.findEntityRanges(character => {\n    const entityKey = character.getEntity();\n    if (entityKey === null) {\n      return false;\n    }\n    // To look for certain types of entities,\n    // or entities with a certain mutability,\n    // you may need to get the entity from contentState.\n    // In this example we get only mutable entities.\n    return contentState.getEntity(entityKey).getMutability() === 'MUTABLE';\n  }, callback);\n};\n```\n\n### Decorator Strategies that find Entities\n\n**Old Syntax**\n\n```js\nfunction findLinkEntities(contentBlock, callback) {\n  contentBlock.findEntityRanges(character => {\n    const entityKey = character.getEntity();\n    return entityKey !== null && Entity.get(entityKey).getType() === 'LINK';\n  }, callback);\n}\n```\n\n**New Syntax**\n\n```js\nfunction findLinkEntities(contentBlock, callback, contentState) {\n  contentBlock.findEntityRanges(character => {\n    const entityKey = character.getEntity();\n    return (\n      entityKey !== null &&\n      contentState.getEntity(entityKey).getType() === 'LINK'\n    );\n  }, callback);\n}\n```\n\n## More Information\n\nSee the [updated examples](https://github.com/facebook/draft-js/tree/master/examples/draft-0-10-0).\n"
  },
  {
    "path": "docs/APIReference-AtomicBlockUtils.md",
    "content": "---\nid: api-reference-atomic-block-utils\ntitle: AtomicBlockUtils\n---\n\nThe `AtomicBlockUtils` module is a static set of utility functions for atomic\nblock editing.\n\nIn each case, these methods accept `EditorState` objects with relevant\nparameters and return `EditorState` objects.\n\n## Static Methods\n\n### `insertAtomicBlock()`\n\n```js\ninsertAtomicBlock: function(\n  editorState: EditorState,\n  entityKey: string,\n  character: string\n): EditorState\n```\n\n### `moveAtomicBlock()`\n\n```js\nmoveAtomicBlock: function(\n  editorState: EditorState,\n  atomicBlock: ContentBlock,\n  targetRange: SelectionState,\n  insertionMode?: DraftInsertionType\n): EditorState\n```\n"
  },
  {
    "path": "docs/APIReference-CharacterMetadata.md",
    "content": "---\nid: api-reference-character-metadata\ntitle: CharacterMetadata\n---\n\n`CharacterMetadata` is an Immutable\n[Record](https://web.archive.org/web/20150623131347/http://facebook.github.io:80/immutable-js/docs/#/Record) \nthat represents inline style and entity information for a single character.\n\n`CharacterMetadata` objects are aggressively pooled and shared. If two characters\nhave the same inline style and entity, they are represented with the same\n`CharacterMetadata` object. We therefore need only as many objects as combinations\nof utilized inline style sets with entity keys, keeping our memory footprint\nsmall even as the contents grow in size and complexity.\n\nTo that end, you should create or apply changes to `CharacterMetadata` objects\nvia the provided set of static methods, which will ensure that pooling is utilized.\n\nMost Draft use cases are unlikely to use these static methods, since most common edit\noperations are already implemented and available via utility modules. The getter\nmethods, however, may come in handy at render time.\n\nSee the API reference on\n[ContentBlock](/docs/api-reference-content-block#representing-styles-and-entities)\nfor information on how `CharacterMetadata` is used within `ContentBlock`.\n\n## Overview\n\n_Static Methods_\n\n<ul class=\"apiIndex\">\n  <li>\n    <a href=\"#create\">\n      <pre>static create(...): CharacterMetadata</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#applystyle\">\n      <pre>static applyStyle(...): CharacterMetadata</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#removestyle\">\n      <pre>static removeStyle(...): CharacterMetadata</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#applyentity\">\n      <pre>static applyEntity(...): CharacterMetadata</pre>\n    </a>\n  </li>\n</ul>\n\n_Methods_\n\n<ul class=\"apiIndex\">\n  <li>\n    <a href=\"#getstyle\">\n      <pre>getStyle(): DraftInlineStyle</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#hasstyle\">\n      <pre>hasStyle(style: string): boolean</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getentity\">\n      <pre>getEntity(): ?string</pre>\n    </a>\n  </li>\n</ul>\n\n## Static Methods\n\nUnder the hood, these methods will utilize pooling to return a matching object,\nor return a new object if none exists.\n\n### `create()`\n\n```js\nstatic create(config?: CharacterMetadataConfig): CharacterMetadata\n```\n\nGenerates a `CharacterMetadata` object from the provided configuration. This\nfunction should be used in lieu of a constructor.\n\nThe configuration will be used to check whether a pooled match for this\nconfiguration already exists. If so, the pooled object will be returned.\nOtherwise, a new `CharacterMetadata` will be pooled for this configuration,\nand returned.\n\n### `applyStyle()`\n\n```js\nstatic applyStyle(\n  record: CharacterMetadata,\n  style: string\n): CharacterMetadata\n```\n\nApply an inline style to this `CharacterMetadata`.\n\n### `removeStyle()`\n\n```js\nstatic removeStyle(\n  record: CharacterMetadata,\n  style: string\n): CharacterMetadata\n```\n\nRemove an inline style from this `CharacterMetadata`.\n\n### `applyEntity()`\n\n```js\nstatic applyEntity(\n  record: CharacterMetadata,\n  entityKey: ?string\n): CharacterMetadata\n```\n\nApply an entity key -- or provide `null` to remove an entity key -- on this\n`CharacterMetadata`.\n\n## Methods\n\n### `getStyle()`\n\n```js\ngetStyle(): DraftInlineStyle\n```\n\nReturns the `DraftInlineStyle` for this character, an `OrderedSet` of strings\nthat represents the inline style to apply for the character at render time.\n\n### `hasStyle()`\n\n```js\nhasStyle(style: string): boolean\n```\n\nReturns whether this character has the specified style.\n\n### `getEntity()`\n\n```js\ngetEntity(): ?string\n```\n\nReturns the entity key (if any) for this character, as mapped to the global set of\nentities tracked by the [`Entity`](https://github.com/facebook/draft-js/blob/master/src/model/entity/DraftEntity.js)\nmodule.\n\nBy tracking a string key here, we can keep the corresponding metadata separate\nfrom the character representation.\n\nIf null, no entity is applied for this character.\n"
  },
  {
    "path": "docs/APIReference-CompositeDecorator.md",
    "content": "---\nid: api-reference-composite-decorator\ntitle: CompositeDecorator\n---\n\n## Advanced Topic Article\n\nSee the [advanced topic article on Decorators](/docs/advanced-topics-decorators#compositedecorator).\n"
  },
  {
    "path": "docs/APIReference-ContentBlock.md",
    "content": "---\nid: api-reference-content-block\ntitle: ContentBlock\n---\n\n`ContentBlock` is an Immutable\n[Record](https://web.archive.org/web/20150623131347/http://facebook.github.io:80/immutable-js/docs/#/Record) \nthat represents the full state of a single block of editor content, including:\n\n- Plain text contents of the block\n- Type, e.g. paragraph, header, list item\n- Entity, inline style, and depth information\n\nA `ContentState` object contains an `OrderedMap` of these `ContentBlock` objects,\nwhich together comprise the full contents of the editor.\n\n`ContentBlock` objects are largely analogous to block-level HTML elements like\nparagraphs and list items. The available types are:\n\n- unstyled\n- paragraph\n- header-one\n- header-two\n- header-three\n- header-four\n- header-five\n- header-six\n- unordered-list-item\n- ordered-list-item\n- blockquote\n- code-block\n- atomic\n\nNew `ContentBlock` objects may be created directly using the constructor.\nExpected Record values are detailed below.\n\n### Representing styles and entities\n\nThe `characterList` field is an immutable `List` containing a `CharacterMetadata`\nobject for every character in the block. This is how we encode styles and\nentities for a given block.\n\nBy making heavy use of immutability and data persistence for these lists and\n`CharacterMetadata` objects, edits to the content generally have little impact\non the memory footprint of the editor.\n\nBy encoding inline styles and entities together in this way, a function that\nperforms edits on a `ContentBlock` can perform slices, concats, and other List\nmethods on a single `List` object.\n\nWhen creating a new `ContentBlock` containing `text` and without `characterList`\nit then will default to a `characterList` with empty `CharacterMetadata` for the\nsupplied text.\n\n## Overview\n\n_Methods_\n\n<ul class=\"apiIndex\">\n  <li>\n    <a href=\"#getkey\">\n      <pre>getKey(): string</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#gettype\">\n      <pre>getType(): DraftBlockType</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#gettext\">\n      <pre>getText(): string</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getcharacterlist\">\n      <pre>getCharacterList(): List&lt;CharacterMetadata&gt;</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getlength\">\n      <pre>getLength(): number</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getdepth\">\n      <pre>getDepth(): number</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getinlinestyleat\">\n      <pre>getInlineStyleAt(offset: number): DraftInlineStyle</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getentityat\">\n      <pre>getEntityAt(offset: number): ?string</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getdata\">\n      <pre>getData(): Map&lt;any, any&gt;</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#findstyleranges\">\n      <pre>findStyleRanges(filterFn: Function, callback: Function): void</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#findentityranges\">\n      <pre>findEntityRanges(filterFn: Function, callback: Function): void</pre>\n    </a>\n  </li>\n</ul>\n\n_Properties_\n\n> Note\n>\n> Use [Immutable Map API](https://web.archive.org/web/20150623131347/http://facebook.github.io:80/immutable-js/docs/#/Map)\n> for the `ContentBlock` constructor or to set properties.\n\n<ul class=\"apiIndex\">\n  <li>\n    <a href=\"#key\">\n      <pre>key: string</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#type\">\n      <pre>type: DraftBlockType</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#text\">\n      <pre>text: string</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#characterlist\">\n      <pre>characterList: List&lt;CharacterMetadata&gt;</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#depth\">\n      <pre>depth: number</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#data\">\n      <pre>data: Map&lt;any, any&gt;</pre>\n    </a>\n  </li>\n</ul>\n\n## Methods\n\n### `getKey()`\n\n```js\ngetKey(): string\n```\n\nReturns the string key for this `ContentBlock`. Block keys are alphanumeric string. It is recommended to use `generateRandomKey` to generate block keys.\n\n### `getType()`\n\n```js\ngetType(): DraftBlockType\n```\n\nReturns the type for this `ContentBlock`. Type values are largely analogous to\nblock-level HTML elements.\n\n### `getText()`\n\n```js\ngetText(): string\n```\n\nReturns the full plaintext for this `ContentBlock`. This value does not contain\nany styling, decoration, or HTML information.\n\n### `getCharacterList()`\n\n```js\ngetCharacterList(): List<CharacterMetadata>\n```\n\nReturns an immutable `List` of `CharacterMetadata` objects, one for each character in the `ContentBlock`. (See [CharacterMetadata](/docs/api-reference-character-metadata) for details.)\n\nThis `List` contains all styling and entity information for the block.\n\n### `getLength()`\n\n```js\ngetLength(): number\n```\n\nReturns the length of the plaintext for the `ContentBlock`.\n\nThis value uses the standard JavaScript `length` property for the string, and is therefore not Unicode-aware -- surrogate pairs will be counted as two characters.\n\n### `getDepth()`\n\n```js\ngetDepth(): number\n```\n\nReturns the depth value for this block, if any. This is currently used only for list items.\n\n### `getInlineStyleAt()`\n\n```js\ngetInlineStyleAt(offset: number): DraftInlineStyle\n```\n\nReturns the `DraftInlineStyle` value (an `OrderedSet<string>`) at a given offset within this `ContentBlock`.\n\n### `getEntityAt()`\n\n```js\ngetEntityAt(offset: number): ?string\n```\n\nReturns the entity key value (or `null` if none) at a given offset within this `ContentBlock`.\n\n### `getData()`\n\n```js\ngetData(): Map<any, any>\n```\n\nReturns block-level metadata.\n\n### `findStyleRanges()`\n\n```js\nfindStyleRanges(\n  filterFn: (value: CharacterMetadata) => boolean,\n  callback: (start: number, end: number) => void\n): void\n```\n\nExecutes a callback for each contiguous range of styles within this `ContentBlock`.\n\n### `findEntityRanges()`\n\n```js\nfindEntityRanges(\n  filterFn: (value: CharacterMetadata) => boolean,\n  callback: (start: number, end: number) => void\n): void\n```\n\nExecutes a callback for each contiguous range of entities within this `ContentBlock`.\n\n## Properties\n\n> Note\n>\n> Use [Immutable Map API](https://web.archive.org/web/20150623131347/http://facebook.github.io:80/immutable-js/docs/#/Map)\n> for the `ContentBlock` constructor or to set properties.\n\n### `key`\n\nSee `getKey()`.\n\n### `text`\n\nSee `getText()`.\n\n### `type`\n\nSee `getType()`.\n\n### `characterList`\n\nSee `getCharacterList()`.\n\n### `depth`\n\nSee `getDepth()`.\n\n### `data`\n\nSee `getData()`.\n"
  },
  {
    "path": "docs/APIReference-ContentState.md",
    "content": "---\nid: api-reference-content-state\ntitle: ContentState\n---\n\n`ContentState` is an Immutable\n[Record](https://web.archive.org/web/20150623131347/http://facebook.github.io:80/immutable-js/docs/#/Record) \nthat represents the full state of:\n\n- The entire **contents** of an editor: text, block and inline styles, and entity ranges.\n- Two **selection states** of an editor: before and after the rendering of these contents.\n\nThe most common use for the `ContentState` object is via `EditorState.getCurrentContent()`,\nwhich provides the `ContentState` currently being rendered in the editor.\n\nAn `EditorState` object maintains undo and redo stacks comprised of `ContentState`\nobjects.\n\n## Overview\n\n_Static Methods_\n\n<ul class=\"apiIndex\">\n  <li>\n    <a href=\"#createfromtext\">\n      <pre>static createFromText(text: string): ContentState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#createfromblockarray\">\n      <pre>static createFromBlockArray(blocks: Array&lt;ContentBlock&gt;): ContentState</pre>\n    </a>\n  </li>\n</ul>\n\n_Methods_\n\n<ul class=\"apiIndex\">\n  <li>\n    <a href=\"#getentitymap\">\n      <pre>getEntityMap()</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getblockmap\">\n      <pre>getBlockMap()</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getselectionbefore\">\n      <pre>getSelectionBefore()</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getselectionafter\">\n      <pre>getSelectionAfter()</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getblockforkey\">\n      <pre>getBlockForKey(key)</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getkeybefore\">\n      <pre>getKeyBefore(key)</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getkeyafter\">\n      <pre>getKeyAfter(key)</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getblockbefore\">\n      <pre>getBlockBefore(key)</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getblockafter\">\n      <pre>getBlockAfter(key)</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getblocksasarray\">\n      <pre>getBlocksAsArray()</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getfirstblock\">\n      <pre>getFirstBlock()</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getlastblock\">\n      <pre>getLastBlock()</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getplaintext\">\n      <pre>getPlainText(delimiter)</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getlastcreatedentitykey\">\n      <pre>getLastCreatedEntityKey()</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#hastext\">\n      <pre>hasText()</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#createentity\">\n      <pre>createEntity(...)</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getentity\">\n      <pre>getEntity(...)</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#mergeentitydata\">\n      <pre>mergeEntityData(...)</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#replaceentitydata\">\n      <pre>replaceEntityData(...)</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#addentity\">\n      <pre>addEntity(...)</pre>\n    </a>\n  </li>\n</ul>\n\n_Properties_\n\n> Use [Immutable Map API](https://web.archive.org/web/20150623131347/http://facebook.github.io:80/immutable-js/docs/#/Map) to\n> set properties.\n>\n> **Example**\n>\n> ```js\n> const editorState = EditorState.createEmpty();\n> const contentState = editorState.getCurrentContent();\n> const contentStateWithSelectionBefore = contentState.set(\n>   'selectionBefore',\n>   SelectionState.createEmpty(contentState.getBlockForKey('1pu4d')),\n> );\n> ```\n\n<ul class=\"apiIndex\">\n  <li>\n    <a href=\"#blockmap\">\n      <pre>blockMap</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#selectionbefore\">\n      <pre>selectionBefore</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#selectionafter\">\n      <pre>selectionAfter</pre>\n    </a>\n  </li>\n</ul>\n\n## Static Methods\n\n### `createFromText()`\n\n```js\nstatic createFromText(\n  text: string,\n  delimiter?: string\n): ContentState\n```\n\nGenerates a `ContentState` from a string, with a delimiter to split the string\ninto `ContentBlock` objects. If no delimiter is provided, '`\\n`' is used.\n\n### `createFromBlockArray()`\n\n```js\nstatic createFromBlockArray(\n  blocks: Array<ContentBlock>,\n  entityMap: ?OrderedMap\n): ContentState\n```\n\nGenerates a `ContentState` from an array of `ContentBlock` objects. The default\n`selectionBefore` and `selectionAfter` states have the cursor at the start of\nthe content.\n\n## Methods\n\n### `getEntityMap()`\n\n```js\ngetEntityMap(): EntityMap\n```\n\nReturns an object store containing all `DraftEntity` records that have been\ncreated. In upcoming v0.11.0 the map returned will be an Immutable ordered map\nof `DraftEntity` records.\n\nIn most cases, you should be able to use the convenience methods below to target\nspecific `DraftEntity` records or obtain information about the state of the\ncontent.\n\n### `getBlockMap()`\n\n```js\ngetBlockMap(): BlockMap\n```\n\nReturns the full ordered map of `ContentBlock` objects representing the state\nof an entire document.\n\nIn most cases, you should be able to use the convenience methods below to target\nspecific `ContentBlock` objects or obtain information about the state of the content.\n\n### `getSelectionBefore()`\n\n```js\ngetSelectionBefore(): SelectionState\n```\n\nReturns the `SelectionState` displayed in the editor before rendering `blockMap`.\n\nWhen performing an `undo` action in the editor, the `selectionBefore` of the current\n`ContentState` is used to place the selection range in the appropriate position.\n\n### `getSelectionAfter()`\n\n```js\ngetSelectionAfter(): SelectionState\n```\n\nReturns the `SelectionState` displayed in the editor after rendering `blockMap`.\n\nWhen performing any action in the editor that leads to this `blockMap` being rendered,\nthe selection range will be placed in the `selectionAfter` position.\n\n### `getBlockForKey()`\n\n```js\ngetBlockForKey(key: string): ContentBlock\n```\n\nReturns the `ContentBlock` corresponding to the given block key.\n\n#### Example\n\n```js\nvar {editorState} = this.state;\nvar startKey = editorState.getSelection().getStartKey();\nvar selectedBlockType = editorState\n  .getCurrentContent()\n  .getBlockForKey(startKey)\n  .getType();\n```\n\n### `getKeyBefore()`\n\n```js\ngetKeyBefore(key: string): ?string\n```\n\nReturns the key before the specified key in `blockMap`, or null if this is the first key.\n\n### `getKeyAfter()`\n\n```js\ngetKeyAfter(key: string): ?string\n```\n\nReturns the key after the specified key in `blockMap`, or null if this is the last key.\n\n### `getBlockBefore()`\n\n```js\ngetBlockBefore(key: string): ?ContentBlock\n```\n\nReturns the `ContentBlock` before the specified key in `blockMap`, or null if this is\nthe first key.\n\n### `getBlockAfter()`\n\n```js\ngetBlockAfter(key: string): ?ContentBlock\n```\n\nReturns the `ContentBlock` after the specified key in `blockMap`, or null if this is the last key.\n\n### `getBlocksAsArray()`\n\n```js\ngetBlocksAsArray(): Array<ContentBlock>\n```\n\nReturns the values of `blockMap` as an array.\n\nYou generally won't need to use this method, since `getBlockMap` provides an `OrderedMap` that you should use for iteration.\n\n### `getFirstBlock()`\n\n```js\ngetFirstBlock(): ContentBlock\n```\n\nReturns the first `ContentBlock`.\n\n### `getLastBlock()`\n\n```js\ngetLastBlock(): ContentBlock\n```\n\nReturns the last `ContentBlock`.\n\n### `getPlainText()`\n\n```js\ngetPlainText(delimiter?: string): string\n```\n\nReturns the full plaintext value of the contents, joined with a delimiter. If no\ndelimiter is specified, the line feed character (`\\u000A`) is used.\n\n### `getLastCreatedEntityKey()`\n\n```js\ngetLastCreatedEntityKey(): string\n```\n\nReturns the string key that can be used to reference the most recently created\n`DraftEntity` record. This is because entities are referenced by their string\nkey in ContentState. The string value should be used within CharacterMetadata\nobjects to track the entity for annotated characters.\n\n### `hasText()`\n\n```js\nhasText(): boolean\n```\n\nReturns whether the contents contain any text at all.\n\n### `createEntity()`\n\n```js\ncreateEntity(\n  type: DraftEntityType,\n  mutability: DraftEntityMutability,\n  data?: Object\n): ContentState\n```\n\nReturns `ContentState` record updated to include the newly created `DraftEntity` record in it's `EntityMap`. Call `getLastCreatedEntityKey` to get the key of the newly created `DraftEntity` record.\n\n### `getEntity()`\n\n```js\ngetEntity(key: string): DraftEntityInstance\n```\n\nReturns the DraftEntityInstance for the specified key. Throws if no instance exists for that key.\n\n### `mergeEntityData()`\n\n```js\nmergeEntityData(\n  key: string,\n  toMerge: {[key: string]: any}\n): ContentState\n```\n\nSince DraftEntityInstance objects are immutable, you cannot update an entity's\nmetadata through typical mutative means.\n\nThe mergeData method allows you to apply updates to the specified entity.\n\n### `replaceEntityData()`\n\n```js\nreplaceEntityData(\n  key: string,\n  newData: {[key: string]: any}\n): ContentState\n```\n\nThe replaceData method is similar to the mergeData method, except it will totally discard the existing data value for the instance and replace it with the specified newData.\n\n### `addEntity()`\n\n```js\naddEntity(instance: DraftEntityInstance): ContentState\n```\n\nIn most cases, you will use contentState.createEntity(). This is a convenience\nmethod that you probably will not need in typical Draft usage.\n\nThe add function is useful in cases where the instances have already been\ncreated, and now need to be added to the Entity store. This may occur in cases\nwhere a vanilla JavaScript representation of a ContentState is being revived for\nediting.\n\n## Properties\n\n> Use [Immutable Map API](https://web.archive.org/web/20150623131347/http://facebook.github.io:80/immutable-js/docs/#/Map) to\n> set properties.\n\n### `blockMap`\n\nSee `getBlockMap()`.\n\n### `selectionBefore`\n\nSee `getSelectionBefore()`.\n\n### `selectionAfter`\n\nSee `getSelectionAfter()`.\n"
  },
  {
    "path": "docs/APIReference-Data-Conversion.md",
    "content": "---\nid: api-reference-data-conversion\ntitle: Data Conversion\n---\n\nBecause a text editor doesn't exist in a vacuum and it's important to save\ncontents for storage or transmission, you will want to be able to\nconvert a `ContentState` into raw JS, and vice versa.\n\nTo that end, we provide a couple of utility functions that allow you to perform\nthese conversions.\n\nNote that the Draft library does not currently provide utilities to convert to\nand from markdown or markup, since different clients may have different requirements\nfor these formats. We instead provide JavaScript objects that can be converted\nto other formats as needed.\n\nThe Flow type [`RawDraftContentState`](https://github.com/facebook/draft-js/blob/master/src/model/encoding/RawDraftContentState.js)\ndenotes the expected structure of the raw format of the contents. The raw state\ncontains a list of content blocks, as well as a map of all relevant entity\nobjects.\n\n## Functions\n\n### `convertFromRaw()`\n\n```js\nconvertFromRaw(rawState: RawDraftContentState): ContentState\n```\n\nGiven a raw state, convert it to a `ContentState`. This is useful when\nrestoring contents to use within a Draft editor.\n\n### `convertToRaw()`\n\n```js\nconvertToRaw(contentState: ContentState): RawDraftContentState\n```\n\nGiven a `ContentState` object, convert it to a raw JS structure. This is useful\nwhen saving an editor state for storage, conversion to other formats, or\nother usage within an application.\n\n### `convertFromHTML()`\n\n```js\nconst sampleMarkup =\n  '<b>Bold text</b>, <i>Italic text</i><br/ ><br />' +\n  '<a href=\"http://www.facebook.com\">Example link</a>';\n\nconst blocksFromHTML = convertFromHTML(sampleMarkup);\nconst state = ContentState.createFromBlockArray(\n  blocksFromHTML.contentBlocks,\n  blocksFromHTML.entityMap,\n);\n\nthis.state = {\n  editorState: EditorState.createWithContent(state),\n};\n```\n\nGiven an HTML fragment, convert it to an object with two keys; one holding the\narray of `ContentBlock` objects, and the other holding a reference to the\nentityMap. Construct content state from the array of block elements and the\nentityMap, and then update the editor state with it. Full example available\n[here](https://github.com/facebook/draft-js/tree/master/examples/draft-0-10-0/convertFromHTML).\n"
  },
  {
    "path": "docs/APIReference-Editor.md",
    "content": "---\nid: api-reference-editor\ntitle: Editor Component\n---\n\nThis article discusses the API and props of the core controlled contentEditable\ncomponent itself, `Editor`. Props are defined within\n[`DraftEditorProps`](https://github.com/facebook/draft-js/blob/master/src/component/base/DraftEditorProps.js).\n\n## Props\n\n## Basics\n\nSee [API Basics](/docs/quickstart-api-basics) for an introduction.\n\n### `editorState`\n\n```js\neditorState: EditorState;\n```\n\nThe `EditorState` object to be rendered by the `Editor`.\n\n### `onChange`\n\n```js\nonChange: (editorState: EditorState) => void\n```\n\nThe `onChange` function to be executed by the `Editor` when edits and selection\nchanges occur.\n\n## Presentation (Optional)\n\n### `placeholder`\n\n```js\nplaceholder?: string\n```\n\nOptional placeholder string to display when the editor is empty.\n\nNote: You can use CSS to style or hide your placeholder as needed. For instance,\nin the [rich editor example](https://github.com/facebook/draft-js/tree/master/examples/draft-0-10-0/rich), the placeholder is hidden when the user changes block styling in an empty editor.\nThis is because the placeholder may not line up with the cursor when the style\nis changed.\n\n### `textAlignment`\n\n```js\ntextAlignment?: DraftTextAlignment\n```\n\nOptionally set the overriding text alignment for this editor. This alignment value will\napply to the entire contents, regardless of default text direction for input text.\n\nYou may use this if you wish to center your text or align it flush in one direction\nto fit it within your UI design.\n\nIf this value is not set, text alignment will be based on the characters within\nthe editor, on a per-block basis.\n\n### `textDirectionality`\n\n```js\ntextDirectionality?: DraftTextDirectionality\n```\n\nOptionally set the overriding text directionality for this editor. The values include 'RTL' for right-to-left text, like Hebrew or Arabic, and 'LTR' for left-to-right text, like English or Spanish. This directionality will apply to the entire contents, regardless of default text direction for input text.\n\nIf this value is not set, text directionality will be based on the characters\nwithin the editor, on a per-block basis.\n\n### `blockRendererFn`\n\n```js\nblockRendererFn?: (block: ContentBlock) => ?Object\n```\n\nOptionally set a function to define custom block rendering. See [Advanced Topics: Block Components](/docs/advanced-topics-block-components) for details on usage.\n\n### `blockRenderMap`\n\n```js\nblockRenderMap?: DraftBlockRenderMap\n```\n\nProvide a map of block rendering configurations. Each block type maps to element tag and an optional react element wrapper. This configuration is used for both rendering and paste processing. See\n[Advanced Topics: Custom Block Rendering](/docs/advanced-topics-custom-block-render-map) for details on usage.\n\n### `blockStyleFn`\n\n```js\nblockStyleFn?: (block: ContentBlock) => string\n```\n\nOptionally set a function to define class names to apply to the given block when it is rendered. See [Advanced Topics: Block Styling](/docs/advanced-topics-block-styling) for details on usage.\n\n### customStyleMap\n\n```js\ncustomStyleMap?: Object\n```\n\nOptionally define a map of inline styles to apply to spans of text with the specified style. See [Advanced Topics: Inline Styles](/docs/advanced-topics-inline-styles) for details on usage.\n\n### `customStyleFn`\n\n```js\ncustomStyleFn?: (style: DraftInlineStyle, block: ContentBlock) => ?Object\n```\n\nOptionally define a function to transform inline styles to CSS objects that are applied to spans of text. See [Advanced Topics: Inline Styles](/docs/advanced-topics-inline-styles) for details on usage.\n\n## Behavior (Optional)\n\n### `autoCapitalize`\n\n```js\nautoCapitalize?: string\n```\n\nSet if auto capitalization is turned on and how it behaves. More about platform availability and usage can [be found on mdn](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input#attr-autocapitalize).\n\n### `autoComplete`\n\n```js\nautoComplete?: string\n```\n\nSet if auto complete is turned on and how it behaves. More about platform availability and usage can [be found on mdn](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input#attr-autocomplete).\n\n### `autoCorrect`\n\n```js\nautoCorrect?: string\n```\n\nSet if auto correct is turned on and how it behaves. More about platform availability and usage can [be found on MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input#attr-autocorrect).\n\n### `readOnly`\n\n```js\nreadOnly?: boolean\n```\n\nSet whether the editor should be rendered as static DOM, with all editability disabled.\n\nThis is useful when supporting interaction within [custom block components](/docs/advanced-topics-block-components) or if you only want to display content for a static use case.\n\nDefault is `false`.\n\n### `spellCheck`\n\n```js\nspellCheck?: boolean\n```\n\nSet whether spellcheck is turned on for your editor.\n\nNote that in OSX Safari, enabling spellcheck also enables autocorrect, if the user\nhas it turned on. Also note that spellcheck is always disabled in IE, since the events\nneeded to observe spellcheck events are not fired in IE.\n\nDefault is `false`.\n\n### `stripPastedStyles`\n\n```js\nstripPastedStyles?: boolean\n```\n\nSet whether to remove all information except plaintext from pasted content.\n\nThis should be used if your editor does not support rich styles.\n\nDefault is `false`.\n\n## DOM and Accessibility (Optional)\n\n### `tabIndex`\n\n### ARIA props\n\nThese props allow you to set accessibility properties on your editor. See\n[DraftEditorProps](https://github.com/facebook/draft-js/blob/master/src/component/base/DraftEditorProps.js) for the exhaustive list of supported attributes.\n\n### `editorKey`\n\n```js\neditorKey?: string\n```\n\nYou probably won't set `editorKey` on an `<Editor />` manually unless you're\nrendering a Draft component serverside. If you _are_, you must set this prop\nto avoid server/client mismatches.\n\nIf the key is not set, it is generated automatically when the component\nrenders and assigned as a prop of the Editor's `<DraftEditorContents />`\ncomponent.\n\nIf you _do_ set this prop, the key should be unique _per-editor_, as it is\nused to determine if styles should be preserved when pasting text within an\neditor.\n\n## Cancelable Handlers (Optional)\n\nThese prop functions are provided to allow custom event handling for a small\nset of useful events. By returning `'handled'` from your handler, you indicate that\nthe event is handled and the Draft core should do nothing more with it. By returning\n`'not-handled'`, you defer to Draft to handle the event.\n\n### `handleReturn`\n\n```js\nhandleReturn?: (\n  e: SyntheticKeyboardEvent,\n  editorState: EditorState,\n) => DraftHandleValue\n```\n\nHandle a `RETURN` keydown event. Example usage: Choosing a mention tag from a\nrendered list of results to trigger applying the mention entity to your content.\n\n### `handleKeyCommand`\n\n```js\nhandleKeyCommand?: (\n  command: string,\n  editorState: EditorState,\n  eventTimeStamp: number,\n) => DraftHandleValue\n```\n\nHandle the named editor command. See\n[Advanced Topics: Key Bindings](/docs/advanced-topics-key-bindings)\nfor details on usage.\n\n### `handleBeforeInput`\n\n```js\nhandleBeforeInput?: (\n  chars: string,\n  editorState: EditorState,\n  eventTimeStamp: number,\n) => DraftHandleValue\n```\n\nHandle the characters to be inserted from a `beforeInput` event. Returning `'handled'`\ncauses the default behavior of the `beforeInput` event to be prevented (i.e. it is\nthe same as calling the `preventDefault` method on the event).\nExample usage: After a user has typed `-` at the start of a new block, you might\nconvert that `ContentBlock` into an `unordered-list-item`.\n\nAt Facebook, we also use this to convert typed ASCII quotes into \"smart\" quotes,\nand to convert typed emoticons into images.\n\n### `handlePastedText`\n\n```js\nhandlePastedText?: (\n  text: string,\n  html?: string,\n  editorState: EditorState,\n) => DraftHandleValue\n```\n\nHandle text and html(for rich text) that has been pasted directly into the editor. Returning true will prevent the default paste behavior.\n\n### `handlePastedFiles`\n\n```js\nhandlePastedFiles?: (files: Array<Blob>) => DraftHandleValue\n```\n\nHandle files that have been pasted directly into the editor.\n\n### `handleDroppedFiles`\n\n```js\nhandleDroppedFiles?: (\n  selection: SelectionState,\n  files: Array<Blob>,\n) => DraftHandleValue\n```\n\nHandle files that have been dropped into the editor.\n\n### `handleDrop`\n\n```js\nhandleDrop?: (\n  selection: SelectionState,\n  dataTransfer: Object,\n  isInternal: DraftDragType,\n) => DraftHandleValue\n```\n\nHandle other drop operations.\n\n## Key Handlers (Optional)\n\nDraft lets you supply a custom `keyDown` handler that wraps or overrides its\ndefault one.\n\n### `keyBindingFn`\n\n```js\nkeyBindingFn?: (e: SyntheticKeyboardEvent) => ?string\n```\n\nThis prop function exposes `keyDown` events to a handler of your choosing. If an\nevent of interest happens, you can perform custom logic and/or return a string\ncorresponding to a `DraftEditorCommand` or a custom editor command of your\nown creation. Example: At Facebook, this is used to provide keyboard interaction\nfor the mentions autocomplete menu that appears when typing a friend's name.\nYou can find a more detailed explanation of this\n[here](/docs/advanced-topics-key-bindings).\n\n## Mouse events\n\n### `onFocus`\n\n```js\nonFocus?: (e: SyntheticFocusEvent) => void\n```\n\n### `onBlur`\n\n```js\nonBlur?: (e: SyntheticFocusEvent) => void\n```\n\n## Methods\n\n### `focus`\n\n```js\nfocus(): void\n```\n\nForce focus back onto the editor node.\n\n### `blur`\n\n```js\nblur(): void\n```\n\nRemove focus from the editor node.\n"
  },
  {
    "path": "docs/APIReference-EditorChangeType.md",
    "content": "---\nid: api-reference-editor-change-type\ntitle: EditorChangeType\n---\n\n[EditorChangeType](https://github.com/facebook/draft-js/blob/master/src/model/immutable/EditorChangeType.js)\nis an enum that lists the possible set of change operations that can be handled\nthe Draft model. It is represented as a Flow type, as a union of strings.\n\nIt is passed as a parameter to `EditorState.push`, and denotes the type of\nchange operation that is being performed by transitioning to the new\n`ContentState`.\n\nBehind the scenes, this value is used to determine appropriate undo/redo\nhandling, spellcheck behavior, and more. Therefore, while it is possible to\nprovide an arbitrary string value as the `changeType` parameter here, you should\navoid doing so.\n\nWe highly recommend that you install [Flow](http://flowtype.org) to perform\nstatic typechecking on your project. Flow will enforce the use of an appropriate\n`EditorChangeType` value.\n\n## Values\n\n### `adjust-depth`\n\nThe `depth` value of one or more `ContentBlock` objects is being changed.\n\n### `apply-entity`\n\nAn entity is being applied (or removed via `null`) to one or more characters.\n\n### `backspace-character`\n\nA single character is being backward-removed.\n\n### `change-block-data`\n\nThe `data` value of one or more `ContentBlock` objects is being changed.\n\n### `change-block-type`\n\nThe `type` value of one or more `ContentBlock` objects is being changed.\n\n### `change-inline-style`\n\nAn inline style is being applied or removed for one or more characters.\n\n### `move-block`\n\nA block is being moved within the [BlockMap](https://github.com/facebook/draft-js/blob/master/src/model/immutable/BlockMap.js).\n\n### `delete-character`\n\nA single character is being forward-removed.\n\n### `insert-characters`\n\nOne or more characters is being inserted at a selection state.\n\n### `insert-fragment`\n\nA \"fragment\" of content (i.e. a\n[BlockMap](https://github.com/facebook/draft-js/blob/master/src/model/immutable/BlockMap.js))\nis being inserted at a selection state.\n\n### `redo`\n\nA redo operation is being performed. Since redo behavior is handled by the\nDraft core, it is unlikely that you will need to use this explicitly.\n\n### `remove-range`\n\nMultiple characters or blocks are being removed.\n\n### `spellcheck-change`\n\nA spellcheck or autocorrect change is being performed. This is used to inform\nthe core editor whether to try to allow native undo behavior.\n\n### `split-block`\n\nA single `ContentBlock` is being split into two, for instance when the user\npresses return.\n\n### `undo`\n\nAn undo operation is being performed. Since undo behavior is handled by the\nDraft core, it is unlikely that you will need to use this explicitly.\n"
  },
  {
    "path": "docs/APIReference-EditorState.md",
    "content": "---\nid: api-reference-editor-state\ntitle: EditorState\n---\n\n`EditorState` is the top-level state object for the editor.\n\nIt is an Immutable \n[Record](https://web.archive.org/web/20150623131347/http://facebook.github.io:80/immutable-js/docs/#/Record)\nthat represents the entire state of a Draft editor, including:\n\n- The current text content state\n- The current selection state\n- The fully decorated representation of the contents\n- Undo/redo stacks\n- The most recent type of change made to the contents\n\n> Note\n>\n> You should not use the Immutable API when using EditorState objects.\n> Instead, use the instance getters and static methods below.\n\n## Overview\n\n_Common instance methods_\n\nThe list below includes the most commonly used instance methods for `EditorState` objects.\n\n<ul class=\"apiIndex\">\n  <li>\n    <a href=\"#getcurrentcontent\">\n      <pre>getCurrentContent(): ContentState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getselection\">\n      <pre>getSelection(): SelectionState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getcurrentinlinestyle\">\n      <pre>getCurrentInlineStyle(): DraftInlineStyle</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getblocktree\">\n      <pre>getBlockTree(): OrderedMap</pre>\n    </a>\n  </li>\n</ul>\n\n_Static Methods_\n\n<ul class=\"apiIndex\">\n  <li>\n    <a href=\"#createempty\">\n      <pre>static createEmpty(?decorator): EditorState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#createwithcontent\">\n      <pre>static createWithContent(contentState, ?decorator): EditorState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#create\">\n      <pre>static create(config): EditorState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#push\">\n      <pre>static push(editorState, contentState, changeType): EditorState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#undo\">\n      <pre>static undo(editorState): EditorState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#redo\">\n      <pre>static redo(editorState): EditorState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#acceptselection\">\n      <pre>static acceptSelection(editorState, selectionState): EditorState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#forceselection\">\n      <pre>static forceSelection(editorState, selectionState): EditorState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#moveselectiontoend\">\n      <pre>static moveSelectionToEnd(editorState): EditorState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#movefocustoend\">\n      <pre>static moveFocusToEnd(editorState): EditorState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#setinlinestyleoverride\">\n      <pre>static setInlineStyleOverride(editorState, inlineStyleOverride): EditorState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#set\">\n      <pre>static set(editorState, EditorStateRecordType): EditorState</pre>\n    </a>\n  </li>\n</ul>\n\n_Properties_\n\n> Note\n>\n> Use the static `EditorState` methods to set properties, rather than using\n> the Immutable API directly. This means using `EditorState.set` to pass\n> new options to an EditorState instance.\n>\n> **Example**\n>\n> ```js\n> const editorState = EditorState.createEmpty();\n> const editorStateWithoutUndo = EditorState.set(editorState, {\n>   allowUndo: false,\n> });\n> ```\n\n<ul class=\"apiIndex\">\n  <li>\n    <a href=\"#allowundo\">\n      <pre>allowUndo</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#currentcontent\">\n      <pre>currentContent</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#decorator\">\n      <pre>decorator</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#directionmap\">\n      <pre>directionMap</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#forceselection\">\n      <pre>forceSelection</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#incompositionmode\">\n      <pre>inCompositionMode</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#inlinestyleoverride\">\n      <pre>inlineStyleOverride</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#lastchangetype\">\n      <pre>lastChangeType</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#nativelyrenderedcontent\">\n      <pre>nativelyRenderedContent</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#redostack\">\n      <pre>redoStack</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#selection\">\n      <pre>selection</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#treemap\">\n      <pre>treeMap</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#undostack\">\n      <pre>undoStack</pre>\n    </a>\n  </li>\n</ul>\n\n## Common Instance Methods\n\n### `getCurrentContent`\n\n```js\ngetCurrentContent(): ContentState\n```\n\nReturns the current contents of the editor.\n\n### `getSelection`\n\n```js\ngetSelection(): SelectionState\n```\n\nReturns the current cursor/selection state of the editor.\n\n### `getCurrentInlineStyle`\n\n```js\ngetCurrentInlineStyle(): DraftInlineStyle\n```\n\nReturns an `OrderedSet<string>` that represents the \"current\" inline style\nfor the editor.\n\nThis is the inline style value that would be used if a character were inserted\nfor the current `ContentState` and `SelectionState`, and takes into account\nany inline style overrides that should be applied.\n\n### `getBlockTree`\n\n```js\ngetBlockTree(blockKey: string): List;\n```\n\nReturns an Immutable `List` of decorated and styled ranges. This is used for\nrendering purposes, and is generated based on the `currentContent` and\n`decorator`.\n\nAt render time, this object is used to break the contents into the appropriate\nblock, decorator, and styled range components.\n\n## Static Methods\n\n### `createEmpty`\n\n```js\nstatic createEmpty(decorator?: DraftDecoratorType): EditorState\n```\n\nReturns a new `EditorState` object with an empty `ContentState` and default\nconfiguration.\n\n### `createWithContent`\n\n```js\nstatic createWithContent(\n  contentState: ContentState,\n  decorator?: DraftDecoratorType\n): EditorState\n```\n\nReturns a new `EditorState` object based on the `ContentState` and decorator\nprovided.\n\n### `create`\n\n```js\nstatic create(config: EditorStateCreationConfig): EditorState\n```\n\nReturns a new `EditorState` object based on a configuration object. Use this\nif you need custom configuration not available via the methods above.\n\n### `push`\n\n```js\nstatic push(\n  editorState: EditorState,\n  contentState: ContentState,\n  changeType: EditorChangeType\n): EditorState\n```\n\nReturns a new `EditorState` object with the specified `ContentState` applied\nas the new `currentContent`. Based on the `changeType`, this `ContentState`\nmay be regarded as a boundary state for undo/redo behavior.\n\nAll content changes must be applied to the EditorState with this method.\n\n_To be renamed._\n\n### `undo`\n\n```js\nstatic undo(editorState: EditorState): EditorState\n```\n\nReturns a new `EditorState` object with the top of the undo stack applied\nas the new `currentContent`.\n\nThe existing `currentContent` is pushed onto the `redo` stack.\n\n### `redo`\n\n```js\nstatic redo(editorState: EditorState): EditorState\n```\n\nReturns a new `EditorState` object with the top of the redo stack applied as the new `currentContent`.\n\nThe existing `currentContent` is pushed onto the `undo` stack.\n\n### `acceptSelection`\n\n```js\nstatic acceptSelection(\n  editorState: EditorState,\n  selectionState: SelectionState\n): EditorState\n```\n\nReturns a new `EditorState` object with the specified `SelectionState` applied,\nbut without requiring the selection to be rendered.\n\nFor example, this is useful when the DOM selection has changed outside of our\ncontrol, and no re-renders are necessary.\n\n### `forceSelection`\n\n```js\nstatic forceSelection(\n  editorState: EditorState,\n  selectionState: SelectionState\n): EditorState\n```\n\nReturns a new `EditorState` object with the specified `SelectionState` applied,\nforcing the selection to be rendered.\n\nThis is useful when the selection should be manually rendered in the correct\nlocation to maintain control of the rendered output.\n\n### `moveSelectionToEnd`\n\n```js\nstatic moveSelectionToEnd(editorState: EditorState): EditorState\n```\n\nReturns a new `EditorState` object with the selection at the end.\n\nMoves selection to the end of the editor without forcing focus.\n\n### `moveFocusToEnd`\n\n```js\nstatic moveFocusToEnd(editorState: EditorState): EditorState\n```\n\nReturns a new `EditorState` object with selection at the end and forces focus.\n\nThis is useful in scenarios where we want to programmatically focus the input\nand it makes sense to allow the user to continue working seamlessly.\n\n### `setInlineStyleOverride`\n\n```js\nstatic setInlineStyleOverride(editorState: EditorState, inlineStyleOverride: DraftInlineStyle): EditorState\n```\n\nReturns a new `EditorState` object with the specified `DraftInlineStyle` applied\nas the set of inline styles to be applied to the next inserted characters.\n\n### `set`\n\n```js\nstatic set(editorState: EditorState, options: EditorStateRecordType): EditorState\n```\n\nReturns a new `EditorState` object with new options passed in. The method is\ninherited from the Immutable `record` API.\n\n## Properties and Getters\n\nIn most cases, the instance and static methods above should be sufficient to\nmanage the state of your Draft editor.\n\nBelow is the full list of properties tracked by an `EditorState`, as well as\ntheir corresponding getter methods, to better provide detail on the scope of the\nstate tracked in this object.\n\n> Note\n>\n> You should not use the Immutable API when using EditorState objects.\n> Instead, use the instance getters and static methods above.\n\n### `allowUndo`\n\n```js\nallowUndo: boolean;\ngetAllowUndo();\n```\n\nWhether to allow undo/redo behavior in this editor. Default is `true`.\n\nSince the undo/redo stack is the major source of memory retention, if you have\nan editor UI that does not require undo/redo behavior, you might consider\nsetting this to `false`.\n\n### `currentContent`\n\n```js\ncurrentContent: ContentState;\ngetCurrentContent();\n```\n\nThe currently rendered `ContentState`. See [getCurrentContent()](#getcurrentcontent).\n\n### `decorator`\n\n```js\ndecorator: ?DraftDecoratorType;\ngetDecorator()\n```\n\nThe current decorator object, if any.\n\nNote that the `ContentState` is independent of your decorator. If a decorator\nis provided, it will be used to decorate ranges of text for rendering.\n\n### `directionMap`\n\n```js\ndirectionMap: BlockMap;\ngetDirectionMap();\n```\n\nA map of each block and its text direction, as determined by UnicodeBidiService.\n\nYou should not manage this manually.\n\n### `forceSelection`\n\n```js\nforceSelection: boolean;\nmustForceSelection();\n```\n\nWhether to force the current `SelectionState` to be rendered.\n\nYou should not set this property manually -- see\n[`forceSelection()`](#forceselection).\n\n### `inCompositionMode`\n\n```js\ninCompositionMode: boolean;\nisInCompositionMode();\n```\n\nWhether the user is in IME composition mode. This is useful for rendering the\nappropriate UI for IME users, even when no content changes have been committed\nto the editor. You should not set this property manually.\n\n### `inlineStyleOverride`\n\n```js\ninlineStyleOverride: DraftInlineStyle;\ngetInlineStyleOverride();\n```\n\nAn inline style value to be applied to the next inserted characters. This is\nused when keyboard commands or style buttons are used to apply an inline style\nfor a collapsed selection range.\n\n`DraftInlineStyle` is a type alias for an immutable `OrderedSet` of strings,\neach of which corresponds to an inline style.\n\n### `lastChangeType`\n\n```js\nlastChangeType: EditorChangeType;\ngetLastChangeType();\n```\n\nThe type of content change that took place in order to bring us to our current\n`ContentState`. This is used when determining boundary states for undo/redo.\n\n### `nativelyRenderedContent`\n\n```js\nnativelyRenderedContent: ?ContentState;\ngetNativelyRenderedContent()\n```\n\nDuring edit behavior, the editor may allow certain actions to render natively.\nFor instance, during normal typing behavior in the contentEditable-based component,\nwe can typically allow key events to fall through to print characters in the DOM.\nIn doing so, we can avoid extra re-renders and preserve spellcheck highlighting.\n\nWhen allowing native rendering behavior, it is appropriate to use the\n`nativelyRenderedContent` property to indicate that no re-render is necessary\nfor this `EditorState`.\n\n### `redoStack`\n\n```js\nredoStack: Stack<ContentState>;\ngetRedoStack()\n```\n\nAn immutable stack of `ContentState` objects that can be resurrected for redo\noperations. When performing an undo operation, the current `ContentState` is\npushed onto the `redoStack`.\n\nYou should not manage this property manually. If you would like to disable\nundo/redo behavior, use the `allowUndo` property.\n\nSee also [undoStack](#undostack).\n\n### `selection`\n\n```js\nselection: SelectionState;\ngetSelection();\n```\n\nThe currently rendered `SelectionState`. See [acceptSelection()](#acceptselection)\nand [forceSelection()](#forceselection).\n\nYou should not manage this property manually.\n\n### `treeMap`\n\n```js\ntreeMap: OrderedMap<string, List>;\n```\n\nThe fully decorated and styled tree of ranges to be rendered in the editor\ncomponent. The `treeMap` object is generated based on a `ContentState` and an\noptional decorator (`DraftDecoratorType`).\n\nAt render time, components should iterate through the `treeMap` object to\nrender decorated ranges and styled ranges, using the [getBlockTree()](#getblocktree)\nmethod.\n\nYou should not manage this property manually.\n\n### `undoStack`\n\n```js\nundoStack: Stack<ContentState>;\ngetUndoStack()\n```\n\nAn immutable stack of `ContentState` objects that can be restored for undo\noperations.\n\nWhen performing operations that modify contents, we determine whether the\ncurrent `ContentState` should be regarded as a \"boundary\" state that the user\ncan reach by performing an undo operation. If so, the `ContentState` is pushed\nonto the `undoStack`. If not, the outgoing `ContentState` is discarded.\n\nYou should not manage this property manually. If you would like to disable\nundo/redo behavior, use the `allowUndo` property.\n\nSee also [`redoStack`](#redostack).\n"
  },
  {
    "path": "docs/APIReference-Entity.md",
    "content": "---\nid: api-reference-entity\ntitle: Entity\n---\n\n`Entity` is a static module containing the API for creating, retrieving, and\nupdating entity objects, which are used for annotating text ranges with metadata.\nThis module also houses the single store used to maintain entity data.\n\nThis article is dedicated to covering the details of the API. See the\n[advanced topics article on entities](/docs/advanced-topics-entities)\nfor more detail on how entities may be used.\n\nPlease note that the API for entity storage and management has changed recently;\nfor details on updating your application\n[see our v0.10 API Migration Guide](/docs/v0-10-api-migration#content).\n\nEntity objects returned by `Entity` methods are represented as\n[DraftEntityInstance](https://github.com/facebook/draft-js/blob/master/src/model/entity/DraftEntityInstance.js) immutable records. These have a small set of getter functions and should\nbe used only for retrieval.\n\n## Overview\n\n_Methods_\n\n<ul class=\"apiIndex\">\n  <li>\n    <a href=\"#create\">\n      <pre>create(...): DraftEntityInstance</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#add\">\n      <pre>add(instance: DraftEntityInstance): string</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#get\">\n      <pre>get(key: string): DraftEntityInstance</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#mergedata\">\n      <pre>mergeData(...): DraftEntityInstance</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#replacedata\">\n      <pre>replaceData(...): DraftEntityInstance</pre>\n    </a>\n  </li>\n</ul>\n\n## Methods\n\n### `create` _(Deprecated in favour of [`contentState.createEntity`](/docs/api-reference-content-state#createentity))_\n\n```js\ncreate(\n  type: DraftEntityType,\n  mutability: DraftEntityMutability,\n  data?: Object\n): string\n```\n\nThe `create` method should be used to generate a new entity object with the\nsupplied properties.\n\nNote that a string is returned from this function. This is because entities\nare referenced by their string key in `ContentState`. The string value should\nbe used within `CharacterMetadata` objects to track the entity for annotated\ncharacters.\n\n### `add` _(Deprecated in favour of [`contentState.addEntity`](/docs/api-reference-content-state#addentity))_\n\n```js\nadd(instance: DraftEntityInstance): string\n```\n\nIn most cases, you will use `Entity.create()`. This is a convenience method\nthat you probably will not need in typical Draft usage.\n\nThe `add` function is useful in cases where the instances have already been\ncreated, and now need to be added to the `Entity` store. This may occur in cases\nwhere a vanilla JavaScript representation of a `ContentState` is being revived\nfor editing.\n\n### `get` _(Deprecated in favour of [`contentState.getEntity`](/docs/api-reference-content-state#getentity))_\n\n```js\nget(key: string): DraftEntityInstance\n```\n\nReturns the `DraftEntityInstance` for the specified key. Throws if no instance\nexists for that key.\n\n### `mergeData` _(Deprecated in favour of [`contentState.mergeEntityData`](/docs/api-reference-content-state#mergeentitydata))_\n\n```js\nmergeData(\n  key: string,\n  toMerge: {[key: string]: any}\n): DraftEntityInstance\n```\n\nSince `DraftEntityInstance` objects are immutable, you cannot update an entity's\nmetadata through typical mutative means.\n\nThe `mergeData` method allows you to apply updates to the specified entity.\n\n### `replaceData` _(Deprecated in favour of [`contentState.replaceEntityData`](/docs/api-reference-content-state#replaceentitydata))_\n\n```js\nreplaceData(\n  key: string,\n  newData: {[key: string]: any}\n): DraftEntityInstance\n```\n\nThe `replaceData` method is similar to the `mergeData` method, except it will\ntotally discard the existing `data` value for the instance and replace it with\nthe specified `newData`.\n"
  },
  {
    "path": "docs/APIReference-KeyBindingUtil.md",
    "content": "---\nid: api-reference-key-binding-util\ntitle: KeyBindingUtil\n---\n\nThe `KeyBindingUtil` module is a static set of utility functions for\ndefining key bindings.\n\n## Static Methods\n\n### `isCtrlKeyCommand()`\n\n```js\nisCtrlKeyCommand: function(\n  e: SyntheticKeyboardEvent\n): boolean\n```\n\nCheck whether the `ctrlKey` modifier is _not_ being used in conjunction with\nthe `altKey` modifier. If they are combined, the result is an `altGraph`\nkey modifier, which is not handled by this set of key bindings.\n\n### `isOptionKeyCommand()`\n\n```js\nisOptionKeyCommand: function(\n  e: SyntheticKeyboardEvent\n): boolean\n```\n\n### `usesMacOSHeuristics()`\n\n```js\nusesMacOSHeuristics: function(): boolean\n```\n\nCheck whether heuristics that only apply to macOS are used internally, for\nexample when determining the key combination used as command modifier.\n\n### `hasCommandModifier()`\n\n```js\nhasCommandModifier: function(\n  e: SyntheticKeyboardEvent\n): boolean\n```\n"
  },
  {
    "path": "docs/APIReference-Modifier.md",
    "content": "---\nid: api-reference-modifier\ntitle: Modifier\n---\n\nThe `Modifier` module is a static set of utility functions that encapsulate common\nedit operations on `ContentState` objects. It is highly recommended that you use\nthese methods for edit operations.\n\nThese methods also take care of removing or modifying entity ranges appropriately,\ngiven the mutability types of any affected entities.\n\nIn each case, these methods accept `ContentState` objects with relevant\nparameters and return `ContentState` objects. The returned `ContentState`\nwill be the same as the input object if no edit was actually performed.\n\n## Overview\n\n_Methods_\n\n<ul class=\"apiIndex\">\n  <li>\n    <a href=\"#replacetext\">\n      <pre>replaceText(...): ContentState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#inserttext\">\n      <pre>insertText(...): ContentState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#movetext\">\n      <pre>moveText(...): ContentState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#replacewithfragment\">\n      <pre>replaceWithFragment(...): ContentState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#removerange\">\n      <pre>removeRange(...): ContentState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#splitblock\">\n      <pre>splitBlock(...): ContentState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#applyinlinestyle\">\n      <pre>applyInlineStyle(...): ContentState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#removeinlinestyle\">\n      <pre>removeInlineStyle(...): ContentState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#setblocktype\">\n      <pre>setBlockType(...): ContentState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#setblockdata\">\n      <pre>setBlockData(...): ContentState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#mergeblockdata\">\n      <pre>mergeBlockData(...): ContentState</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#applyentity\">\n      <pre>applyEntity(...): ContentState</pre>\n    </a>\n  </li>\n</ul>\n\n## Static Methods\n\n### `replaceText()`\n\n```js\nreplaceText(\n  contentState: ContentState,\n  rangeToReplace: SelectionState,\n  text: string,\n  inlineStyle?: DraftInlineStyle,\n  entityKey?: ?string\n): ContentState\n```\n\nReplaces the specified range of this `ContentState` with the supplied string,\nwith the inline style and entity key applied to the entire inserted string.\n\nExample: On Facebook, when replacing `@abraham lincoln` with a mention of\nAbraham Lincoln, the entire old range is the target to replace and the mention\nentity should be applied to the inserted string.\n\n### `insertText()`\n\n```js\ninsertText(\n  contentState: ContentState,\n  targetRange: SelectionState,\n  text: string,\n  inlineStyle?: DraftInlineStyle,\n  entityKey?: ?string\n): ContentState\n```\n\nIdentical to `replaceText`, but enforces that the target range is collapsed\nso that no characters are replaced. This is only for convenience, since text\nedits are so often insertions rather than replacements.\n\n### `moveText()`\n\n```js\nmoveText(\n  contentState: ContentState,\n  removalRange: SelectionState,\n  targetRange: SelectionState\n): ContentState\n```\n\nMoves the \"removal\" range to the \"target\" range, replacing the target text.\n\n### `replaceWithFragment()`\n\n```js\nreplaceWithFragment(\n  contentState: ContentState,\n  targetRange: SelectionState,\n  fragment: BlockMap\n): ContentState\n```\n\nA \"fragment\" is a section of a block map, effectively only an\n`OrderedMap<string, ContentBlock>` much the same as the full block map of a\n`ContentState` object.\n\nThis method will replace the \"target\" range with the fragment.\n\nExample: When pasting content, we convert the paste into a fragment to be inserted\ninto the editor, then use this method to add it.\n\n### `removeRange()`\n\n```js\nremoveRange(\n  contentState: ContentState,\n  rangeToRemove: SelectionState,\n  removalDirection: DraftRemovalDirection\n): ContentState\n```\n\nRemove an entire range of text from the editor. The removal direction is important\nfor proper entity deletion behavior.\n\n### `splitBlock()`\n\n```js\nsplitBlock(\n  contentState: ContentState,\n  selectionState: SelectionState\n): ContentState\n```\n\nSplit the selected block into two blocks. This should only be used if the\nselection is collapsed.\n\n### `applyInlineStyle()`\n\n```js\napplyInlineStyle(\n  contentState: ContentState,\n  selectionState: SelectionState,\n  inlineStyle: string\n): ContentState\n```\n\nApply the specified inline style to the entire selected range.\n\n### `removeInlineStyle()`\n\n```js\nremoveInlineStyle(\n  contentState: ContentState,\n  selectionState: SelectionState,\n  inlineStyle: string\n): ContentState\n```\n\nRemove the specified inline style from the entire selected range.\n\n### `setBlockType()`\n\n```js\nsetBlockType(\n  contentState: ContentState,\n  selectionState: SelectionState,\n  blockType: DraftBlockType\n): ContentState\n```\n\nSet the block type for all selected blocks.\n\n### `setBlockData()`\n\n```js\nsetBlockData(\n  contentState: ContentState,\n  selectionState: SelectionState,\n  blockData: Map<any, any>\n): ContentState\n```\n\nSet the block data for all selected blocks.\n\n### `mergeBlockData()`\n\n```js\nmergeBlockData(\n  contentState: ContentState,\n  selectionState: SelectionState,\n  blockData: Map<any, any>\n): ContentState\n```\n\nUpdate block data for all selected blocks.\n\n### `applyEntity()`\n\n```js\napplyEntity(\n  contentState: ContentState,\n  selectionState: SelectionState,\n  entityKey: ?string\n): ContentState\n```\n\nApply an entity to the entire selected range, or remove all entities from the range if `entityKey` is `null`.\n"
  },
  {
    "path": "docs/APIReference-RichUtils.md",
    "content": "---\nid: api-reference-rich-utils\ntitle: RichUtils\n---\n\nThe `RichUtils` module is a static set of utility functions for rich text\nediting.\n\nIn each case, these methods accept `EditorState` objects with relevant\nparameters and return `EditorState` objects.\n\n## Static Methods\n\n### `currentBlockContainsLink()`\n\n```js\ncurrentBlockContainsLink(\n  editorState: EditorState\n): boolean\n```\n\n### `getCurrentBlockType()`\n\n```js\ngetCurrentBlockType(\n  editorState: EditorState\n): string\n```\n\n### `handleKeyCommand()`\n\n```js\nhandleKeyCommand(\n  editorState: EditorState,\n  command: string\n): ?EditorState\n```\n\n### `insertSoftNewline()`\n\n```js\ninsertSoftNewline(\n  editorState: EditorState\n): EditorState\n```\n\n### `onBackspace()`\n\n```js\nonBackspace(\n  editorState: EditorState\n): EditorState?\n```\n\n### `onDelete()`\n\n```js\nonDelete(\n  editorState: EditorState\n): EditorState?\n```\n\n### `onTab()`\n\n```js\nonTab(\n  event: SyntheticEvent,\n  editorState: EditorState,\n  maxDepth: integer\n): EditorState\n```\n\n### `toggleBlockType()`\n\n```js\ntoggleBlockType(\n  editorState: EditorState,\n  blockType: string\n): EditorState\n```\n\n### `toggleCode()`\n\n```js\ntoggleCode(\n  editorState: EditorState\n): EditorState\n```\n\n### `toggleInlineStyle()`\n\n```js\ntoggleInlineStyle(\n  editorState: EditorState,\n  inlineStyle: string\n): EditorState\n```\n\nToggle the specified inline style for the selection. If the\nuser's selection is collapsed, apply or remove the style for the\ninternal state. If it is not collapsed, apply the change directly\nto the document state.\n\n### `toggleLink()`\n\n```js\ntoggleLink(\n  editorState: EditorState,\n  targetSelection: SelectionState,\n  entityKey: string\n): EditorState\n```\n\n### `tryToRemoveBlockStyle()`\n\n```js\ntryToRemoveBlockStyle(\n  editorState: EditorState\n): ContentState?\n```\n"
  },
  {
    "path": "docs/APIReference-SelectionState.md",
    "content": "---\nid: api-reference-selection-state\ntitle: SelectionState\n---\n\n`SelectionState` is an Immutable \n[Record](https://web.archive.org/web/20150623131347/http://facebook.github.io:80/immutable-js/docs/#/Record) \nthat represents a selection range in the editor.\n\nThe most common use for the `SelectionState` object is via `EditorState.getSelection()`,\nwhich provides the `SelectionState` currently being rendered in the editor.\n\n### Keys and Offsets\n\nA selection range has two points: an **anchor** and a **focus**. (Read more on\n[MDN](https://developer.mozilla.org/en-US/docs/Web/API/Selection#Glossary)).\n\nThe native DOM approach represents each point as a Node/offset pair, where the offset\nis a number corresponding either to a position within a Node's `childNodes` or, if the\nNode is a text node, a character offset within the text contents.\n\nSince Draft maintains the contents of the editor using `ContentBlock` objects,\nwe can use our own model to represent these points. Thus, selection points are\ntracked as key/offset pairs, where the `key` value is the key of the `ContentBlock`\nwhere the point is positioned and the `offset` value is the character offset\nwithin the block.\n\n### Start/End vs. Anchor/Focus\n\nThe concept of **anchor** and **focus** is very useful when actually rendering\na selection state in the browser, as it allows us to use forward and backward\nselection as needed. For editing operations, however, the direction of the selection\ndoesn't matter. In this case, it is more appropriate to think in terms of\n**start** and **end** points.\n\nThe `SelectionState` therefore exposes both anchor/focus values and\nstart/end values. When managing selection behavior, we recommend that\nyou work with _anchor_ and _focus_ values to maintain selection direction.\nWhen managing content operations, however, we recommend that you use _start_\nand _end_ values.\n\nFor instance, when extracting a slice of text from a block based on a\n`SelectionState`, it is irrelevant whether the selection is backward:\n\n```js\nvar selectionState = editorState.getSelection();\nvar anchorKey = selectionState.getAnchorKey();\nvar currentContent = editorState.getCurrentContent();\nvar currentContentBlock = currentContent.getBlockForKey(anchorKey);\nvar start = selectionState.getStartOffset();\nvar end = selectionState.getEndOffset();\nvar selectedText = currentContentBlock.getText().slice(start, end);\n```\n\nNote that `SelectionState` itself tracks only _anchor_ and _focus_ values.\n_Start_ and _end_ values are derived.\n\n## Overview\n\n_Static Methods_\n\n<ul class=\"apiIndex\">\n  <li>\n    <a href=\"#createempty\">\n      <pre>static createEmpty(blockKey)</pre>\n    </a>\n  </li>\n</ul>\n\n_Methods_\n\n<ul class=\"apiIndex\">\n  <li>\n    <a href=\"#getstartkey\">\n      <pre>getStartKey()</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getstartoffset\">\n      <pre>getStartOffset()</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getendkey\">\n      <pre>getEndKey()</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getendoffset\">\n      <pre>getEndOffset()</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getanchorkey\">\n      <pre>getAnchorKey()</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getanchoroffset\">\n      <pre>getAnchorOffset()</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getfocuskey\">\n      <pre>getFocusKey()</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getfocusoffset\">\n      <pre>getFocusOffset()</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#getisbackward\">\n      <pre>getIsBackward()</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#gethasfocus\">\n      <pre>getHasFocus()</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#iscollapsed\">\n      <pre>isCollapsed()</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#hasedgewithin\">\n      <pre>hasEdgeWithin(blockKey, start, end)</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#serialize\">\n      <pre>serialize()</pre>\n    </a>\n  </li>\n</ul>\n\n_Properties_\n\n> Use [Immutable Map API](https://web.archive.org/web/20150623131347/http://facebook.github.io:80/immutable-js/docs/#/Map) to\n> set properties.\n>\n> **Example**\n>\n> ```js\n> const selectionState = SelectionState.createEmpty();\n> const selectionStateWithNewFocusOffset = selection.set('focusOffset', 1);\n> ```\n\n<ul class=\"apiIndex\">\n  <li>\n    <a href=\"#anchorkey\">\n      <pre>anchorKey</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#anchoroffset\">\n      <pre>anchorOffset</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#focuskey\">\n      <pre>focusKey</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#focusoffset\">\n      <pre>focusOffset</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#isbackward\">\n      <pre>isBackward</pre>\n    </a>\n  </li>\n  <li>\n    <a href=\"#hasfocus\">\n      <pre>hasFocus</pre>\n    </a>\n  </li>\n</ul>\n\n## Static Methods\n\n### `createEmpty()`\n\n```js\ncreateEmpty(blockKey: string): SelectionState\n```\n\nCreate a `SelectionState` object at the zero offset of the provided block key\nand `hasFocus` set to false.\n\n## Methods\n\n### `getStartKey()`\n\n```js\ngetStartKey(): string\n```\n\nReturns the key of the block containing the start position of the selection range.\n\n### `getStartOffset()`\n\n```js\ngetStartOffset(): number\n```\n\nReturns the block-level character offset of the start position of the selection range.\n\n### `getEndKey()`\n\n```js\ngetEndKey(): string\n```\n\nReturns the key of the block containing the end position of the selection range.\n\n### `getEndOffset()`\n\n```js\ngetEndOffset(): number\n```\n\nReturns the block-level character offset of the end position of the selection range.\n\n### `getAnchorKey()`\n\n```js\ngetAnchorKey(): string\n```\n\nReturns the key of the block containing the anchor position of the selection range.\n\n### `getAnchorOffset()`\n\n```js\ngetAnchorOffset(): number\n```\n\nReturns the block-level character offset of the anchor position of the selection range.\n\n### `getFocusKey()`\n\n```js\ngetFocusKey(): string\n```\n\nReturns the key of the block containing the focus position of the selection range.\n\n### `getFocusOffset()`\n\n```js\ngetFocusOffset(): number\n```\n\nReturns the block-level character offset of the focus position of the selection range.\n\n### `getIsBackward()`\n\n```js\ngetIsBackward(): boolean\n```\n\nReturns whether the focus position is before the anchor position in the document.\n\nThis must be derived from the key order of the active `ContentState`, or if the selection\nrange is entirely within one block, a comparison of the anchor and focus offset values.\n\n### `getHasFocus()`\n\n```js\ngetHasFocus(): boolean\n```\n\nReturns whether the editor has focus.\n\n### `isCollapsed()`\n\n```js\nisCollapsed(): boolean\n```\n\nReturns whether the selection range is collapsed, i.e. a caret. This is true\nwhen the anchor and focus keys are the same /and/ the anchor and focus offsets\nare the same.\n\n### `hasEdgeWithin()`\n\n```js\nhasEdgeWithin(blockKey: string, start: number, end: number): boolean\n```\n\nReturns whether the selection range has an edge that overlaps with the specified\nstart/end range within a given block.\n\nThis is useful when setting DOM selection within a block after contents are\nrendered.\n\n### `serialize()`\n\n```js\nserialize(): string\n```\n\nReturns a serialized version of the `SelectionState`. Useful for debugging.\n\n## Properties\n\n> Use [Immutable Map API](https://web.archive.org/web/20150623131347/http://facebook.github.io:80/immutable-js/docs/#/Map) to\n> set properties.\n\n```js\nvar selectionState = SelectionState.createEmpty('foo');\nvar updatedSelection = selectionState.merge({\n  focusKey: 'bar',\n  focusOffset: 0,\n});\nvar anchorKey = updatedSelection.getAnchorKey(); // 'foo'\nvar focusKey = updatedSelection.getFocusKey(); // 'bar'\n```\n\n### `anchorKey`\n\nThe block containing the anchor end of the selection range.\n\n### `anchorOffset`\n\nThe offset position of the anchor end of the selection range.\n\n### `focusKey`\n\nThe block containing the focus end of the selection range.\n\n### `focusOffset`\n\nThe offset position of the focus end of the selection range.\n\n### `isBackward`\n\nIf the anchor position is lower in the document than the focus position, the selection is backward. Note: The `SelectionState` is an object with no knowledge of the `ContentState` structure. Therefore, when updating `SelectionState` values, you are responsible for updating `isBackward` as well.\n\n### `hasFocus`\n\nWhether the editor currently has focus.\n"
  },
  {
    "path": "docs/Advanced-Topics-Block-Components.md",
    "content": "---\nid: advanced-topics-block-components\ntitle: Custom Block Components\n---\n\nDraft is designed to solve problems for straightforward rich text interfaces\nlike comments and chat messages, but it also powers richer editor experiences\nlike [Facebook Notes](https://www.facebook.com/notes/).\n\nUsers can embed images within their Notes, either loading from their existing\nFacebook photos or by uploading new images from the desktop. To that end,\nthe Draft framework supports custom rendering at the block level, to render\ncontent like rich media in place of plain text.\n\nThe [TeX editor](https://github.com/facebook/draft-js/tree/master/examples/draft-0-10-0/tex)\nin the Draft repository provides a live example of custom block rendering, with\nTeX syntax translated on the fly into editable embedded formula rendering via the\n[KaTeX library](https://khan.github.io/KaTeX/).\n\nA [media example](https://github.com/facebook/draft-js/tree/master/examples/draft-0-10-0/media) is also\navailable, which showcases custom block rendering of audio, image, and video.\n\nBy using a custom block renderer, it is possible to introduce complex rich\ninteractions within the frame of your editor.\n\n## Custom Block Components\n\nWithin the `Editor` component, one may specify the `blockRendererFn` prop.\nThis prop function allows a higher-level component to define custom React\nrendering for `ContentBlock` objects, based on block type, text, or other\ncriteria.\n\nFor instance, we may wish to render `ContentBlock` objects of type `'atomic'`\nusing a custom `MediaComponent`.\n\n```js\nfunction myBlockRenderer(contentBlock) {\n  const type = contentBlock.getType();\n  if (type === 'atomic') {\n    return {\n      component: MediaComponent,\n      editable: false,\n      props: {\n        foo: 'bar',\n      },\n    };\n  }\n}\n\n// Then...\nimport {Editor} from 'draft-js';\nclass EditorWithMedia extends React.Component {\n  ...\n  render() {\n    return <Editor ... blockRendererFn={myBlockRenderer} />;\n  }\n}\n```\n\nIf no custom renderer object is returned by the `blockRendererFn` function,\n`Editor` will render the default `EditorBlock` text block component.\n\nThe `component` property defines the component to be used, while the optional\n`props` object includes props that will be passed through to the rendered\ncustom component via the `props.blockProps` sub property object. In addition,\nthe optional `editable` property determines whether the custom component is\n`contentEditable`.\n\nIt is strongly recommended that you use `editable: false` if your custom\ncomponent will not contain text.\n\nIf your component contains text as provided by your `ContentState`, your custom\ncomponent should compose an `EditorBlock` component. This will allow the\nDraft framework to properly maintain cursor behavior within your contents.\n\nBy defining this function within the context of a higher-level component,\nthe props for this custom component may be bound to that component, allowing\ninstance methods for custom component props.\n\n## Defining custom block components\n\nWithin `MediaComponent`, the most likely use case is that you will want to\nretrieve entity metadata to render your custom block. You may apply an entity\nkey to the text within a `'atomic'` block during `EditorState` management,\nthen retrieve the metadata for that key in your custom component `render()`\ncode.\n\n```js\nclass MediaComponent extends React.Component {\n  render() {\n    const {block, contentState} = this.props;\n    const {foo} = this.props.blockProps;\n    const data = contentState.getEntity(block.getEntityAt(0)).getData();\n    // Return a <figure> or some other content using this data.\n  }\n}\n```\n\nThe `ContentBlock` object and the `ContentState` record are made available\nwithin the custom component, along with the props defined at the top level. By\nextracting entity information from the `ContentBlock` and the `Entity` map, you\ncan obtain the metadata required to render your custom component.\n\n_Retrieving the entity from the block is admittedly a bit of an awkward API,\nand is worth revisiting._\n\n## Recommendations and other notes\n\nIf your custom block renderer requires mouse interaction, it is often wise\nto temporarily set your `Editor` to `readOnly={true}` during this\ninteraction. In this way, the user does not trigger any selection changes within\nthe editor while interacting with the custom block. This should not be a problem\nwith respect to editor behavior, since interacting with your custom block\ncomponent is most likely mutually exclusive from text changes within the editor.\n\nThe recommendation above is especially important for custom block renderers\nthat involve text input, like the TeX editor example.\n\nIt is also worth noting that within the Facebook Notes editor, we have not\ntried to perform any specific SelectionState rendering or management on embedded\nmedia, such as rendering a highlight on an embedded photo when selecting it.\nThis is in part because of the rich interaction provided on the media\nitself, with resize handles and other controls exposed to mouse behavior.\n\nSince an engineer using Draft has full awareness of the selection state\nof the editor and full control over native Selection APIs, it would be possible\nto build selection behavior on static embedded media if desired. So far, though,\nwe have not tried to solve this at Facebook, so we have not packaged solutions\nfor this use case into the Draft project at this time.\n"
  },
  {
    "path": "docs/Advanced-Topics-Block-Styling.md",
    "content": "---\nid: advanced-topics-block-styling\ntitle: Block Styling\n---\n\nWithin `Editor`, some block types are given default CSS styles to limit the amount\nof basic configuration required to get engineers up and running with custom\neditors.\n\nBy defining a `blockStyleFn` prop function for an `Editor`, it is possible\nto specify classes that should be applied to blocks at render time.\n\n## DraftStyleDefault.css\n\nThe Draft library includes default block CSS styles within\n[DraftStyleDefault.css](https://github.com/facebook/draft-js/blob/master/src/component/utils/DraftStyleDefault.css). _(Note that the annotations on the CSS class names are\nartifacts of Facebook's internal CSS module management system.)_\n\nThese CSS rules are largely devoted to providing default styles for list items,\nwithout which callers would be responsible for managing their own default list\nstyles.\n\n## blockStyleFn\n\nThe `blockStyleFn` prop on `Editor` allows you to define CSS classes to\nstyle blocks at render time. For instance, you may wish to style `'blockquote'`\ntype blocks with fancy italic text.\n\n```js\nfunction myBlockStyleFn(contentBlock) {\n  const type = contentBlock.getType();\n  if (type === 'blockquote') {\n    return 'superFancyBlockquote';\n  }\n}\n\n// Then...\nimport {Editor} from 'draft-js';\nclass EditorWithFancyBlockquotes extends React.Component {\n  render() {\n    return <Editor ... blockStyleFn={myBlockStyleFn} />;\n  }\n}\n```\n\nThen, in your own CSS:\n\n```css\n.superFancyBlockquote {\n  color: #999;\n  font-family: 'Hoefler Text', Georgia, serif;\n  font-style: italic;\n  text-align: center;\n}\n```\n"
  },
  {
    "path": "docs/Advanced-Topics-Custom-Block-Render.md",
    "content": "---\nid: advanced-topics-custom-block-render-map\ntitle: Custom Block Rendering\n---\n\nThis article discusses how to customize Draft default block rendering.\nThe block rendering is used to define supported block types and their respective\nrenderers, as well as converting pasted content to known Draft block types.\n\nWhen pasting content, or when calling\n[convertFromHTML](/docs/api-reference-data-conversion#convertfromhtml),\nDraft will convert pasted content to the respective block rendering type\nby matching the Draft block render map with the matched tag.\n\n## Draft default block render map\n\n| HTML element    | Draft block type                          |\n| --------------- | ----------------------------------------- |\n| `<h1/>`         | header-one                                |\n| `<h2/>`         | header-two                                |\n| `<h3/>`         | header-three                              |\n| `<h4/>`         | header-four                               |\n| `<h5/>`         | header-five                               |\n| `<h6/>`         | header-six                                |\n| `<blockquote/>` | blockquote                                |\n| `<pre/>`        | code-block                                |\n| `<figure/>`     | atomic                                    |\n| `<li/>`         | unordered-list-item,ordered-list-item\\*\\* |\n| `<div/>`        | unstyled\\*\\*\\*                            |\n\n\\*\\* - Block type will be based on the parent `<ul/>` or `<ol/>`\n\n\\*\\*\\* - Any block that is not recognized by the block rendering mapping will be treated as unstyled\n\n## Configuring block render map\n\nDraft's default block render map can be overwritten by passing an\n[Immutable Map](https://web.archive.org/web/20150623131347/http://facebook.github.io:80/immutable-js/docs/#/Map) to\nthe editor blockRender props.\n\n_example of overwriting default block render map:_\n\n```js\n// The example below deliberately only allows\n// 'heading-two' as the only valid block type and\n// updates the unstyled element to also become a h2.\nconst blockRenderMap = Immutable.Map({\n  'header-two': {\n    element: 'h2'\n  },\n  'unstyled': {\n    element: 'h2'\n  }\n});\n\nclass RichEditor extends React.Component {\n  render() {\n    return (\n      <Editor\n        ...\n        blockRenderMap={blockRenderMap}\n      />\n    );\n  }\n}\n```\n\nThere are cases where instead of overwriting the defaults, we only want to add new block types.\nThis can be done by using the DefaultDraftBlockRenderMap reference to create a new blockRenderMap\n\n_example of extending default block render map:_\n\n```js\nconst blockRenderMap = Immutable.Map({\n  'section': {\n    element: 'section'\n  }\n});\n\n// Include 'paragraph' as a valid block and updated the unstyled element but\n// keep support for other draft default block types\nconst extendedBlockRenderMap = Draft.DefaultDraftBlockRenderMap.merge(blockRenderMap);\n\nclass RichEditor extends React.Component {\n  render() {\n    return (\n      <Editor\n        ...\n        blockRenderMap={extendedBlockRenderMap}\n      />\n    );\n  }\n}\n```\n\nWhen Draft parses pasted HTML, it maps from HTML elements back into\nDraft block types. If you want to specify other HTML elements that map to a\nparticular block type, you can add the array `aliasedElements` to the block config.\n\n_example of unstyled block type alias usage:_\n\n```js\n'unstyled': {\n  element: 'div',\n  aliasedElements: ['p'],\n}\n```\n\n## Custom block wrappers\n\nBy default, the html element is used to wrap block types. However, a react component\ncan also be provided to the _blockRenderMap_ to wrap the EditorBlock.\n\nDuring pasting, or when calling\n[convertFromHTML](/docs/api-reference-data-conversion#convertfromhtml),\nthe html will be scanned for matching tag elements. A wrapper will be used when there is a definition for\nit on the _blockRenderMap_ to wrap that particular block type. For example:\n\nDraft uses wrappers to wrap `<li/>` inside either `<ol/>` or `<ul/>`, but wrappers can also be used\nto wrap any other custom block type.\n\n_example of extending default block render map to use a react component for a custom block:_\n\n```js\nclass MyCustomBlock extends React.Component {\n  constructor(props) {\n    super(props);\n  }\n\n  render() {\n    return (\n      <div className='MyCustomBlock'>\n        {/* here, this.props.children contains a <section> container, as that was the matching element */}\n        {this.props.children}\n      </div>\n    );\n  }\n}\n\nconst blockRenderMap = Immutable.Map({\n  'MyCustomBlock': {\n    // element is used during paste or html conversion to auto match your component;\n    // it is also retained as part of this.props.children and not stripped out\n    element: 'section',\n    wrapper: <MyCustomBlock />,\n  }\n});\n\n// keep support for other draft default block types and add our myCustomBlock type\nconst extendedBlockRenderMap = Draft.DefaultDraftBlockRenderMap.merge(blockRenderMap);\n\nclass RichEditor extends React.Component {\n  ...\n  render() {\n    return (\n      <Editor\n        ...\n        blockRenderMap={extendedBlockRenderMap}\n      />\n    );\n  }\n}\n```\n"
  },
  {
    "path": "docs/Advanced-Topics-Decorators.md",
    "content": "---\nid: advanced-topics-decorators\ntitle: Decorators\n---\n\nInline and block styles aren't the only kind of rich styling that we might\nwant to add to our editor. The Facebook comment input, for example, provides\nblue background highlights for mentions and hashtags.\n\nTo support flexibility for custom rich text, Draft provides a \"decorator\"\nsystem. The [tweet example](https://github.com/facebook/draft-js/tree/master/examples/draft-0-10-0/tweet)\noffers a live example of decorators in action.\n\n## CompositeDecorator\n\nThe decorator concept is based on scanning the contents of a given\n[ContentBlock](/docs/api-reference-content-block)\nfor ranges of text that match a defined strategy, then rendering them\nwith a specified React component.\n\nYou can use the `CompositeDecorator` class to define your desired\ndecorator behavior. This class allows you to supply multiple `DraftDecorator`\nobjects, and will search through a block of text with each strategy in turn.\n\nDecorators are stored within the `EditorState` record. When creating a new\n`EditorState` object, e.g. via `EditorState.createEmpty()`, a decorator may\noptionally be provided.\n\n> Under the hood\n>\n> When contents change in a Draft editor, the resulting `EditorState` object\n> will evaluate the new `ContentState` with its decorator, and identify ranges\n> to be decorated. A complete tree of blocks, decorators, and inline styles is\n> formed at this time, and serves as the basis for our rendered output.\n>\n> In this way, we always ensure that as contents change, rendered decorations\n> are in sync with our `EditorState`.\n\nIn the \"Tweet\" editor example, for instance, we use a `CompositeDecorator` that\nsearches for @-handle strings as well as hashtag strings:\n\n```js\nconst compositeDecorator = new CompositeDecorator([\n  {\n    strategy: handleStrategy,\n    component: HandleSpan,\n  },\n  {\n    strategy: hashtagStrategy,\n    component: HashtagSpan,\n  },\n]);\n```\n\nThis composite decorator will first scan a given block of text for @-handle\nmatches, then for hashtag matches.\n\n```js\n// Note: these aren't very good regexes, don't use them!\nconst HANDLE_REGEX = /\\@[\\w]+/g;\nconst HASHTAG_REGEX = /\\#[\\w\\u0590-\\u05ff]+/g;\n\nfunction handleStrategy(contentBlock, callback, contentState) {\n  findWithRegex(HANDLE_REGEX, contentBlock, callback);\n}\n\nfunction hashtagStrategy(contentBlock, callback, contentState) {\n  findWithRegex(HASHTAG_REGEX, contentBlock, callback);\n}\n\nfunction findWithRegex(regex, contentBlock, callback) {\n  const text = contentBlock.getText();\n  let matchArr, start;\n  while ((matchArr = regex.exec(text)) !== null) {\n    start = matchArr.index;\n    callback(start, start + matchArr[0].length);\n  }\n}\n```\n\nThe strategy functions execute the provided callback with the `start` and\n`end` values of the matching range of text.\n\n## Decorator Components\n\nFor your decorated ranges of text, you must define a React component to use\nto render them. These tend to be plain `span` elements with CSS classes or\nstyles applied to them.\n\nIn our current example, the `CompositeDecorator` object names `HandleSpan` and\n`HashtagSpan` as the components to use for decoration. These are basic\nstateless components:\n\n```js\nconst HandleSpan = props => {\n  return (\n    <span {...props} style={styles.handle}>\n      {props.children}\n    </span>\n  );\n};\n\nconst HashtagSpan = props => {\n  return (\n    <span {...props} style={styles.hashtag}>\n      {props.children}\n    </span>\n  );\n};\n```\n\nThe Decorator Component will receive various pieces of metadata in `props`,\nincluding a copy of the `contentState`, the `entityKey` if there is one, and the\n`blockKey`. For a full list of props supplied to a Decorator Component see the\n[DraftDecoratorComponentProps type](https://github.com/facebook/draft-js/blob/master/src/model/decorators/DraftDecorator.js).\n\nNote that `props.children` is passed through to the rendered output. This is\ndone to ensure that the text is rendered within the decorated `span`.\n\nYou can use the same approach for links, as demonstrated in our\n[link example](https://github.com/facebook/draft-js/tree/master/examples/draft-0-10-0/link).\n\n### Beyond CompositeDecorator\n\nThe decorator object supplied to an `EditorState` need only match the expectations\nof the\n[DraftDecoratorType](https://github.com/facebook/draft-js/blob/master/src/model/decorators/DraftDecoratorType.js)\nFlow type definition, which means that you can create any decorator classes\nyou wish, as long as they match the expected type -- you are not bound by\n`CompositeDecorator`.\n\n## Setting new decorators\n\nFurther, it is acceptable to set a new `decorator` value on the `EditorState`\non the fly, during normal state propagation, through immutable means.\n\nThis means that during your app workflow, if your decorator becomes invalid or\nrequires a modification, you can create a new decorator object (or use\n`null` to remove all decorations) and `EditorState.set()` to make use of the new\ndecorator setting.\n\nFor example, if for some reason we wished to disable the creation of @-handle\ndecorations while the user interacts with the editor, it would be fine to do the\nfollowing:\n\n```js\nfunction turnOffHandleDecorations(editorState) {\n  const onlyHashtags = new CompositeDecorator([\n    {\n      strategy: hashtagStrategy,\n      component: HashtagSpan,\n    },\n  ]);\n  return EditorState.set(editorState, {decorator: onlyHashtags});\n}\n```\n\nThe `ContentState` for this `editorState` will be re-evaluated with the new\ndecorator, and @-handle decorations will no longer be present in the next\nrender pass.\n\nAgain, this remains memory-efficient due to data persistence across immutable\nobjects.\n"
  },
  {
    "path": "docs/Advanced-Topics-EditorState-Race-Conditions.md",
    "content": "---\nid: advanced-topics-editorstate-race-conditions\ntitle: EditorState Race Conditions\n---\n\nDraft `Editor` is a _controlled input_ component (you can read about this in detail in the [API Basics](/docs/quickstart-api-basics) section), meaning that changes made to the `Editor` state are propagated upwards through `onChange` and it's up to the app to feed it back to the `Editor` component.\n\nThis cycle usually looks like:\n\n```js\n...\nthis.onChange = function(editorState) {\n  this.setState({editorState: editorState});\n}\n...\n<Editor\n  editorState={this.state.editorState}\n  onChange={this.onChange}\n  placeholder=\"Enter some text...\"\n/>\n```\n\nDifferent browser events can trigger the `Editor` to create a new state and call `onChange`. For instance, when the user pastes text into it, Draft parses the new content and creates the necessary data structure to represent it.\n\nThis cycle works great, however, it is an asynchronous operation because of the `setState` call. This introduces a delay between setting the state and rendering the `Editor` with the new state. During this time period other JS code can be executed.\n\n![Race condition diagram 1](/img/editorstate-race-condition-1-handler.png)\n\nNon-atomic operations like this can potentially introduce race conditions.\nHere's an example: Suppose you want to remove all the text styles that come from the paste. This can be implemented by listening to the onPaste event and removing all styles from the `EditorState`:\n\n```js\nthis.onPaste = function() {\n  this.setState({\n    editorState: removeEditorStyles(this.state.editorState),\n  });\n};\n```\n\nHowever, this won't work as expected. You now have two event handlers that set a new `EditorState` in the exact same browser event. Since the event handlers will run one after the other only the last `setState` will prevail. Here's how it looks like in the JS timeline:\n\n![Race condition diagram 2](/img/editorstate-race-condition-2-handlers.png)\n\nAs you can see, since `setState` is an asynchronous operation, the second `setState` will override whatever it was set on the first one making the `Editor` lose all the contents from the pasted text.\n\nYou can observe and explore the race condition in [this running example](https://jsfiddle.net/qecccw3r/). The example also has logging to highlight the JS timeline so make sure to open the developer tools.\n\nAs a rule of thumb avoid having different event handlers for the same event that manipulate the `EditorState`. Using setTimeout to run `setState` might also land you in the same situation.\nAnytime you feel you're “losing state” make sure you're not overriding it before the `Editor` re-rendering.\n\n## Best Practices\n\nNow that you understand the problem, what can you do to avoid it? In general be mindful of where you're getting the `EditorState` from. If you're using a local one (stored in `this.state`) then there's the potential for it to not be up to date.\nTo minimize this problem Draft offers the latest `EditorState` instance in most of its callback functions. In your code you should use the provided `EditorState` instead of your local one to make sure you're basing your changes on the latest one.\nHere's a list of supported callbacks on the `Editor`:\n\n- `handleReturn(event, editorState)`\n- `handleKeyCommand(command, editorState)`\n- `handleBeforeInput(chars, editorState)`\n- `handlePastedText(text, html, editorState)`\n\nThe paste example can then be re-written in a race condition free way by using these methods:\n\n```js\nthis.handlePastedText = (text, styles, editorState) => {\n  this.setState({\n    editorState: removeEditorStyles(text, editorState),\n  });\n};\n//...\n<Editor\n  editorState={this.state.editorState}\n  onChange={this.onChange}\n  handlePastedText={this.handlePastedText}\n  placeholder=\"Enter some text...\"\n/>;\n```\n\nWith `handlePastedText` you can implement the paste behavior by yourself.\n\nNOTE: If you need to have this behavior in your Editor, you can achieve it by setting the `Editor`'s `stripPastedStyles` property to `true`.\n"
  },
  {
    "path": "docs/Advanced-Topics-Entities.md",
    "content": "---\nid: advanced-topics-entities\ntitle: Entities\n---\n\nThis article discusses the Entity system, which Draft uses for annotating\nranges of text with metadata. Entities introduce levels of richness beyond\nstyled text. Links, mentions, and embedded content can all be implemented\nusing entities.\n\nIn the Draft repository, the\n[link editor](https://github.com/facebook/draft-js/tree/master/examples/draft-0-10-0/link)\nand\n[entity demo](https://github.com/facebook/draft-js/tree/master/examples/draft-0-10-0/entity)\nprovide live code examples to help clarify how entities can be used, as well\nas their built-in behavior.\n\nThe [Entity API Reference](/docs/api-reference-entity) provides\ndetails on the static methods to be used when creating, retrieving, or updating\nentity objects.\n\nFor information about recent changes to the Entity API, and examples of how to\nupdate your application,\n[see our v0.10 API Migration Guide](/docs/v0-10-api-migration#content).\n\n## Introduction\n\nAn entity is an object that represents metadata for a range of text within a\nDraft editor. It has three properties:\n\n- **type**: A string that indicates what kind of entity it is, e.g. `'LINK'`,\n  `'MENTION'`, `'PHOTO'`.\n- **mutability**: Not to be confused with immutability a la `immutable-js`, this\n  property denotes the behavior of a range of text annotated with this entity\n  object when editing the text range within the editor. This is addressed in\n  greater detail below.\n- **data**: An optional object containing metadata for the entity. For instance,\n  a `'LINK'` entity might contain a `data` object that contains the `href` value\n  for that link.\n\nAll entities are stored in the ContentState record. The entities are referenced\nby key within `ContentState` and React components used to decorate annotated\nranges. (We are currently deprecating a previous API for accessing Entities; see\nissue\n[#839](https://github.com/facebook/draft-js/issues/839).)\n\nUsing [decorators](/docs/advanced-topics-decorators) or\n[custom block components](/docs/advanced-topics-block-components), you can\nadd rich rendering to your editor based on entity metadata.\n\n## Creating and Retrieving Entities\n\nEntities should be created using `contentState.createEntity`, which accepts the\nthree properties above as arguments. This method returns a `ContentState` record updated to include the newly created entity, then you can call `contentState.getLastCreatedEntityKey` to get the key of the newly created entity record.\n\nThis key is the value that should be used when applying entities to your\ncontent. For instance, the `Modifier` module contains an `applyEntity` method:\n\n```js\nconst contentState = editorState.getCurrentContent();\nconst contentStateWithEntity = contentState.createEntity('LINK', 'MUTABLE', {\n  url: 'http://www.zombo.com',\n});\nconst entityKey = contentStateWithEntity.getLastCreatedEntityKey();\nconst contentStateWithLink = Modifier.applyEntity(\n  contentStateWithEntity,\n  selectionState,\n  entityKey,\n);\nconst newEditorState = EditorState.set(editorState, {\n  currentContent: contentStateWithLink,\n});\n```\n\nFor a given range of text, then, you can extract its associated entity key by using\nthe `getEntityAt()` method on a `ContentBlock` object, passing in the target\noffset value.\n\n```js\nconst contentState = editorState.getCurrentContent();\nconst blockWithLinkAtBeginning = contentState.getBlockForKey('...');\nconst linkKey = blockWithLinkAtBeginning.getEntityAt(0);\nconst linkInstance = contentState.getEntity(linkKey);\nconst {url} = linkInstance.getData();\n```\n\n## \"Mutability\"\n\nEntities may have one of three \"mutability\" values. The difference between them\nis the way they behave when the user makes edits to them.\n\nNote that `DraftEntityInstance` objects are always immutable Records, and this\nproperty is meant only to indicate how the annotated text may be \"mutated\" within\nthe editor. _(Future changes may rename this property to ward off potential\nconfusion around naming.)_\n\n### Immutable\n\nThis text cannot be altered without removing the entity annotation\nfrom the text. Entities with this mutability type are effectively atomic.\n\nFor instance, in a Facebook input, add a mention for a Page (e.g. Barack Obama).\nThen, either add a character within the mentioned text, or try to delete a character.\nNote that when adding or deleting characters, the entity is removed.\n\nThis mutability value is useful in cases where the text absolutely must match\nits relevant metadata, and may not be altered.\n\n### Mutable\n\nThis text may be altered freely. For instance, link text is\ngenerally intended to be \"mutable\" since the href and linkified text are not\ntightly coupled.\n\n### Segmented\n\nEntities that are \"segmented\" are tightly coupled to their text in much the\nsame way as \"immutable\" entities, but allow customization via deletion.\n\nFor instance, in a Facebook input, add a mention for a friend. Then, add a\ncharacter to the text. Note that the entity is removed from the entire string,\nsince your mentioned friend may not have their name altered in your text.\n\nNext, try deleting a character or word within the mention. Note that only the\nsection of the mention that you have deleted is removed. In this way, we can\nallow short names for mentions.\n\n## Modifying Entities\n\nSince `DraftEntityInstance` records are immutable, you may not update the `data`\nproperty on an instance directly.\n\nInstead, two `Entity` methods are available to modify entities: `mergeData` and\n`replaceData`. The former allows updating data by passing in an object to merge,\nwhile the latter completely swaps in the new data object.\n\n## Using Entities for Rich Content\n\nThe next article in this section covers the usage of decorator objects, which\ncan be used to retrieve entities for rendering purposes.\n\nThe [link editor example](https://github.com/facebook/draft-js/tree/master/examples/draft-0-10-0/link)\nprovides a working example of entity creation and decoration in use.\n"
  },
  {
    "path": "docs/Advanced-Topics-Inline-Styles.md",
    "content": "---\nid: advanced-topics-inline-styles\ntitle: Complex Inline Styles\n---\n\nWithin your editor, you may wish to provide a wide variety of inline style\nbehavior that goes well beyond the bold/italic/underline basics. For instance,\nyou may want to support variety with color, font families, font sizes, and more.\nFurther, your desired styles may overlap or be mutually exclusive.\n\nThe [Rich Editor](http://github.com/facebook/draft-js/tree/master/examples/draft-0-10-0/rich) and\n[Colorful Editor](http://github.com/facebook/draft-js/tree/master/examples/draft-0-10-0/color)\nexamples demonstrate complex inline style behavior in action.\n\n## Model\n\nWithin the Draft model, inline styles are represented at the character level,\nusing an immutable `OrderedSet` to define the list of styles to be applied to\neach character. These styles are identified by string. (See [CharacterMetadata](/docs/api-reference-character-metadata)\nfor details.)\n\nFor example, consider the text \"Hello **world**\". The first six characters of\nthe string are represented by the empty set, `OrderedSet()`. The final five\ncharacters are represented by `OrderedSet.of('BOLD')`. For convenience, we can\nthink of these `OrderedSet` objects as arrays, though in reality we aggressively\nreuse identical immutable objects.\n\nIn essence, our styles are:\n\n```js\n[\n  [], // H\n  [], // e\n  // ...\n  ['BOLD'], // w\n  ['BOLD'], // o\n  // etc.\n];\n```\n\n## Overlapping Styles\n\nNow let's say that we wish to make the middle range of characters italic as well:\nHe*llo* ***wo*rld**. This operation can be performed via the\n[Modifier](/docs/api-reference-modifier) API.\n\nThe end result will accommodate the overlap by including `'ITALIC'` in the\nrelevant `OrderedSet` objects as well.\n\n```js\n[\n  [], // H\n  [], // e\n  ['ITALIC'], // l\n  // ...\n  ['BOLD', 'ITALIC'], // w\n  ['BOLD', 'ITALIC'], // o\n  ['BOLD'], // r\n  // etc.\n];\n```\n\nWhen determining how to render inline-styled text, Draft will identify\ncontiguous ranges of identically styled characters and render those characters\ntogether in styled `span` nodes.\n\n## Mapping a style string to CSS\n\nBy default, `Editor` provides support for a basic list of inline styles:\n`'BOLD'`, `'ITALIC'`, `'UNDERLINE'`, and `'CODE'`. These are mapped to plain CSS\nstyle objects, which are used to apply styles to the relevant ranges.\n\nFor your editor, you may define custom style strings to include with these\ndefaults, or you may override the default style objects for the basic styles.\n\nWithin your `Editor` use case, you may provide the `customStyleMap` prop\nto define your style objects. (See\n[Colorful Editor](http://github.com/facebook/draft-js/tree/master/examples/draft-0-10-0/color)\nfor a live example.)\n\nFor example, you may want to add a `'STRIKETHROUGH'` style. To do so, define a\ncustom style map:\n\n```js\nimport {Editor} from 'draft-js';\n\nconst styleMap = {\n  'STRIKETHROUGH': {\n    textDecoration: 'line-through',\n  },\n};\n\nclass MyEditor extends React.Component {\n  // ...\n  render() {\n    return (\n      <Editor\n        customStyleMap={styleMap}\n        editorState={this.state.editorState}\n        ...\n      />\n    );\n  }\n}\n```\n\nWhen rendered, the `textDecoration: line-through` style will be applied to all\ncharacter ranges with the `STRIKETHROUGH` style.\n"
  },
  {
    "path": "docs/Advanced-Topics-Issues-and-Pitfalls.md",
    "content": "---\nid: advanced-topics-issues-and-pitfalls\ntitle: Issues and Pitfalls\n---\n\nThis article addresses some known issues with the Draft editor framework, as\nwell as some common pitfalls that we have encountered while using the framework\nat Facebook.\n\n## Common Pitfalls\n\n### Delayed state updates\n\nA common pattern for unidirectional data management is to batch or otherwise\ndelay updates to data stores, using a setTimeout or another mechanism. Stores are\nupdated, then emit changes to the relevant React components to propagate\nre-rendering.\n\nWhen delays are introduced to a React application with a Draft editor, however,\nit is possible to cause significant interaction problems. This is because the\neditor expects immediate updates and renders that stay in sync with the user's typing\nbehavior. Delays can prevent updates from being propagated through the editor\ncomponent tree, which can cause a disconnect between keystrokes and updates.\n\nTo avoid this while still using a delaying or batching mechanism, you should\nseparate the delay behavior from your `Editor` state propagation. That is,\nyou must always allow your `EditorState` to propagate to your `Editor`\ncomponent without delay, and independently perform batched updates that do\nnot affect the state of your `Editor` component.\n\n### Missing `Draft.css`\n\nThe Draft framework includes a handful of CSS resources intended for use with\nthe editor, available in a single file via the build, `Draft.css`.\n\nThis CSS should be included when rendering the editor, as these styles set defaults\nfor text alignment, spacing, and other important features. Without it, you may\nencounter issues with block positioning, alignment, and cursor behavior.\n\nIf you choose to write your own CSS independent of `Draft.css`, you will most\nlikely need to replicate much of the default styling.\n\n## Known Issues\n\n### Custom OSX Keybindings\n\nBecause the browser has no access to OS-level custom keybindings, it is not\npossible to intercept edit intent behaviors that do not map to default system\nkey bindings.\n\nThe result of this is that users who use custom keybindings may encounter\nissues with Draft editors, since their key commands may not behave as expected.\n\n### Browser plugins/extensions\n\nAs with any React application, browser plugins and extensions that modify the\nDOM can cause Draft editors to break.\n\nGrammar checkers, for instance, may modify the DOM within contentEditable\nelements, adding styles like underlines and backgrounds. Since React cannot\nreconcile the DOM if the browser does not match its expectations,\nthe editor state may fail to remain in sync with the DOM.\n\nCertain old ad blockers are also known to break the native DOM Selection\nAPI -- a bad idea no matter what! -- and since Draft depends on this API to\nmaintain controlled selection state, this can cause trouble for editor\ninteraction.\n\n### IME and Internet Explorer\n\nAs of IE11, Internet Explorer demonstrates notable issues with certain international\ninput methods, most significantly Korean input.\n\n### Polyfills\n\nSome of Draft's code and that of its dependencies make use of ES2015 language\nfeatures. Syntax features like `class` are compiled away via Babel when Draft is\nbuilt, but it does not include polyfills for APIs now included in many modern\nbrowsers (for instance: `String.prototype.startsWith`). We expect your browser\nsupports these APIs natively or with the assistance of a polyfill. One such\npolyfill is [es6-shim](https://github.com/es-shims/es6-shim), which we use in\nmany examples but you are free to use\n[babel-polyfill](https://babeljs.io/docs/usage/polyfill/) if that's more\nyour scene.\n\nWhen using either polyfill/shim, you should include it as early as possible in\nyour application's entrypoint (at the very minimum, before you import Draft).\nFor instance, using\n[create-react-app](https://github.com/facebookincubator/create-react-app) and\ntargeting IE11, `src/index.js` is probably a good spot to import your polyfill:\n\n**`src/index.js`**\n\n```js\nimport 'babel-polyfill';\n// or\nimport 'es6-shim';\n\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport App from './App';\nimport './index.css';\n\nReactDOM.render(<App />, document.getElementById('root'));\n```\n\n### Mobile Not Yet Supported\n\nDraft.js is moving towards full mobile support, but does not officially support\nmobile browsers at this point. There are some known issues affecting Android and\niOS - see issues tagged\n['android'](https://github.com/facebook/draft-js/labels/android) or\n['ios'](https://github.com/facebook/draft-js/labels/ios) for the current status.\n"
  },
  {
    "path": "docs/Advanced-Topics-Key-Bindings.md",
    "content": "---\nid: advanced-topics-key-bindings\ntitle: Key Bindings\n---\n\nThe `Editor` component offers flexibility to define custom key bindings\nfor your editor, via the `keyBindingFn` prop. This allows you to match key\ncommands to behaviors in your editor component.\n\n## Defaults\n\nThe default key binding function is `getDefaultKeyBinding`.\n\nSince the Draft framework maintains tight control over DOM rendering and\nbehavior, basic editing commands must be captured and routed through the key\nbinding system.\n\n`getDefaultKeyBinding` maps known OS-level editor commands to `DraftEditorCommand`\nstrings, which then correspond to behaviors within component handlers.\n\nFor instance, `Ctrl+Z` (Win) and `Cmd+Z` (OSX) map to the `'undo'` command,\nwhich then routes our handler to perform an `EditorState.undo()`.\n\n## Customization\n\nYou may provide your own key binding function to supply custom command strings.\n\nIt is recommended that your function use `getDefaultKeyBinding` as a\nfall-through case, so that your editor may benefit from default commands.\n\nWith your custom command string, you may then implement the `handleKeyCommand`\nprop function, which allows you to map that command string to your desired\nbehavior. If `handleKeyCommand` returns `'handled'`, the command is considered\nhandled. If it returns `'not-handled'`, the command will fall through.\n\n## Example\n\nLet's say we have an editor that should have a \"Save\" mechanism to periodically\nwrite your contents to the server as a draft copy.\n\nFirst, let's define our key binding function:\n\n```js\nimport {getDefaultKeyBinding, KeyBindingUtil} from 'draft-js';\nconst {hasCommandModifier} = KeyBindingUtil;\n\nfunction myKeyBindingFn(e: SyntheticKeyboardEvent): string | null {\n  if (e.keyCode === 83 /* `S` key */ && hasCommandModifier(e)) {\n    return 'myeditor-save';\n  }\n  return getDefaultKeyBinding(e);\n}\n```\n\nOur function receives a key event, and we check whether it matches our criteria:\nit must be an `S` key, and it must have a command modifier, i.e. the command\nkey for OSX, or the control key otherwise.\n\nIf the command is a match, return a string that names the command. Otherwise,\nfall through to the default key bindings.\n\nIn our editor component, we can then make use of the command via the\n`handleKeyCommand` prop:\n\n```js\nimport {Editor} from 'draft-js';\nclass MyEditor extends React.Component {\n\n  constructor(props) {\n    super(props);\n    this.handleKeyCommand = this.handleKeyCommand.bind(this);\n  }\n  // ...\n\n  handleKeyCommand(command: string): DraftHandleValue {\n    if (command === 'myeditor-save') {\n      // Perform a request to save your contents, set\n      // a new `editorState`, etc.\n      return 'handled';\n    }\n    return 'not-handled';\n  }\n\n  render() {\n    return (\n      <Editor\n        editorState={this.state.editorState}\n        handleKeyCommand={this.handleKeyCommand}\n        keyBindingFn={myKeyBindingFn}\n        ...\n      />\n    );\n  }\n}\n```\n\nThe `'myeditor-save'` command can be used for our custom behavior, and returning\n`'handled'` instructs the editor that the command has been handled and no more work\nis required.\n\nBy returning `'not-handled'` in all other cases, default commands are able to fall\nthrough to default handler behavior.\n"
  },
  {
    "path": "docs/Advanced-Topics-Managing-Focus.md",
    "content": "---\nid: advanced-topics-managing-focus\ntitle: Managing Focus\n---\n\nManaging text input focus can be a tricky task within React components. The browser\nfocus/blur API is imperative, so setting or removing focus via declarative means\npurely through `render()` tends to feel awkward and incorrect, and it requires\nchallenging attempts at controlling focus state.\n\nWith that in mind, at Facebook we often choose to expose `focus()` methods\non components that wrap text inputs. This breaks the declarative paradigm,\nbut it also simplifies the work needed for engineers to successfully manage\nfocus behavior within their apps.\n\nThe `Editor` component follows this pattern, so there is a public `focus()`\nmethod available on the component. This allows you to use a ref within your\nhigher-level component to call `focus()` directly on the component when needed.\n\nThe event listeners within the component will observe focus changes and\npropagate them through `onChange` as expected, so state and DOM will remain\ncorrectly in sync.\n\n## Translating container clicks to focus\n\nYour higher-level component will most likely wrap the `Editor` component in a\ncontainer of some kind, perhaps with padding to style it to match your app.\n\nBy default, if a user clicks within this container but outside of the rendered\n`Editor` while attempting to focus the editor, the editor will have no awareness\nof the click event. It is therefore recommended that you use a click listener\non your container component, and use the `focus()` method described above to\napply focus to your editor.\n\nThe [plaintext editor example](https://github.com/facebook/draft-js/tree/master/examples/draft-0-10-0/plaintext),\nfor instance, uses this pattern.\n"
  },
  {
    "path": "docs/Advanced-Topics-Nested-Lists.md",
    "content": "---\nid: advanced-topics-nested-lists\ntitle: Nested Lists\n---\n\nThe Draft framework provides support for nested lists, as demonstrated in the\nFacebook Notes editor. There, you can use `Tab` and `Shift+Tab` to add or remove\ndepth to a list item.\n\n## Implementation\n\nThe [`RichUtils`](/docs/api-reference-rich-utils) module provides a handy `onTab` method that manages this\nbehavior, and should be sufficient for most nested list needs. You can use\nthe `onTab` prop on your `Editor` to make use of this utility.\n\nBy default, styling is applied to list items to set appropriate spacing and\nlist style behavior, via `DraftStyleDefault.css`.\n\nNote that there is currently no support for handling depth for blocks of any type\nexcept `'ordered-list-item'` and `'unordered-list-item'`.\n"
  },
  {
    "path": "docs/Advanced-Topics-Text-Direction.md",
    "content": "---\nid: advanced-topics-text-direction\ntitle: Text Direction\n---\n\nFacebook supports dozens of languages, which means that our text inputs need\nto be flexible enough to handle considerable variety.\n\nFor example, we want input behavior for RTL languages such as Arabic and Hebrew\nto meet users' expectations. We also want to be able to support editor contents\nwith a mixture of LTR and RTL text.\n\nTo that end, Draft uses a bidi algorithm to determine appropriate\ntext alignment and direction on a per-block basis.\n\nText is rendered with an LTR or RTL direction automatically as the user types.\nYou should not need to do anything to set direction yourself.\n\n## Text Alignment\n\nWhile languages are automatically aligned to the left or right during composition,\nas defined by the content characters, it is also possible for engineers to\nmanually set the text alignment for an editor's contents.\n\nThis may be useful, for instance, if an editor requires strictly centered\ncontents, or needs to keep text aligned flush against another UI element.\n\nThe `Editor` component therefore provides a `textAlignment` prop, with a\nsmall set of values: `'left'`, `'center'`, and `'right'`. Using these values,\nthe contents of your editor will be aligned to the specified direction regardless\nof language and character set.\n"
  },
  {
    "path": "docs/Overview.md",
    "content": "---\nid: getting-started\ntitle: Overview\nonPageNav: 'none'\n---\n\nDraft.js is a framework for building rich text editors in React, powered by an immutable model and abstracting over cross-browser differences.\n\nDraft.js allows you to build any type of rich text input, whether you're only looking to support a few inline text styles or building a complex text editor for composing long-form articles.\n\nDraft.js was introduced at [React.js Conf](https://conf2016.reactjs.org/schedule#rich-text-editing-with-react) in February 2016.\n\n<iframe width=\"100%\" height=\"365\" src=\"https://www.youtube.com/embed/feUYwoLhE_4\" frameBorder=\"0\" allowFullScreen></iframe>\n\n## Installation\n\nDraft.js is distributed via npm. It depends on React and React DOM which must also be installed.\n\n```sh\nnpm install draft-js react react-dom\n# or alternately\nyarn add draft-js react react-dom\n```\n\nDraft.js uses some modern ECMAScript features which are not available to IE11 and not part of create-react-app's default babel config. If you're running into problems out-of-the-box try installing a shim or polyfill alongside Draft.\n\n```sh\nnpm install draft-js react react-dom babel-polyfill\n# or\nyarn add draft-js react react-dom es6-shim\n```\n\nLearn more about [using a shim with Draft](/docs/advanced-topics-issues-and-pitfalls#polyfills).\n\n## API Changes Notice\n\nBefore getting started, please be aware that we recently changed the API of\nEntity storage in Draft. Draft.js version `v0.10.0` and `v0.11.0` support both the old\nand new API. Following that up will be `v0.12.0` which will remove the old API.\n\n## Usage\n\n```js\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport {Editor, EditorState} from 'draft-js';\nimport 'draft-js/dist/Draft.css';\n\nclass MyEditor extends React.Component {\n  constructor(props) {\n    super(props);\n    this.state = {editorState: EditorState.createEmpty()};\n    this.onChange = editorState => this.setState({editorState});\n  }\n\n  render() {\n    return (\n      <Editor editorState={this.state.editorState} onChange={this.onChange} />\n    );\n  }\n}\n\nReactDOM.render(<MyEditor />, document.getElementById('container'));\n```\n\nSince the release of React 16.8, you can use [Hooks](https://reactjs.org/docs/hooks-intro.html) as a way to work with `EditorState` without using a class.\n\n```js\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport {Editor, EditorState} from 'draft-js';\nimport 'draft-js/dist/Draft.css';\n\nfunction MyEditor() {\n  const [editorState, setEditorState] = React.useState(\n    () => EditorState.createEmpty(),\n  );\n\n  return <Editor editorState={editorState} onChange={setEditorState} />;\n}\n\nReactDOM.render(<MyEditor />, document.getElementById('container'));\n```\n\nBecause Draft.js supports unicode, you must have the following meta tag in the `<head></head>` block of your HTML file:\n\n```html\n<meta charset=\"utf-8\" />\n```\n\n`Draft.css` should be included when rendering the editor. Learn more about [why](/docs/advanced-topics-issues-and-pitfalls#missing-draftcss).\n\nNext, let's go into the basics of the API and learn what else you can do with Draft.js.\n"
  },
  {
    "path": "docs/QuickStart-API-Basics.md",
    "content": "---\nid: quickstart-api-basics\ntitle: API Basics\n---\n\nThis document provides an overview of the basics of the `Draft` API. A\n[working example](https://github.com/facebook/draft-js/tree/master/examples/draft-0-10-0/plaintext)\nis also available to follow along.\n\n## Controlled Inputs\n\nThe `Editor` React component is built as a controlled ContentEditable component,\nwith the goal of providing a top-level API modeled on the familiar React\n_controlled input_ API.\n\nAs a brief refresher, controlled inputs involve two key pieces:\n\n1. A _value_ to represent the state of the input\n2. An _onChange_ prop function to receive updates to the input\n\nThis approach allows the component that composes the input to have strict\ncontrol over the state of the input, while still allowing updates to the DOM to\nprovide information about the text that the user has written.\n\n```js\nconst MyInput = () => {\n  const [value, setValue] = useState('');\n  const onChange = (evt) => setValue(evt.target.value);\n\n  return <input value={value} onChange={onChange} />;\n};\n```\n\nThe top-level component can maintain control over the input state via this\n`value` state property.\n\n## Controlling Rich Text\n\nIn a React rich text scenario, however, there are two clear problems:\n\n1. A string of plaintext is insufficient to represent the complex state of a\n   rich editor.\n2. There is no such `onChange` event available for a ContentEditable element.\n\nState is therefore represented as a single immutable\n[EditorState](/docs/api-reference-editor-state) object, and `onChange` is\nimplemented within the `Editor` core to provide this state value to the top\nlevel.\n\nThe `EditorState` object is a complete snapshot of the state of the editor,\nincluding contents, cursor, and undo/redo history. All changes to content and\nselection within the editor will create new `EditorState` objects. Note that\nthis remains efficient due to data persistence across immutable objects.\n\n```js\nimport {Editor, EditorState} from 'draft-js';\n\nconst MyInput = () => {\n  const [editorState, setEditorState] = useState(() =>\n    EditorState.createEmpty(),\n  );\n\n  return <Editor editorState={editorState} onChange={setEditorState} />;\n};\n```\n\nFor any edits or selection changes that occur in the editor DOM, your `onChange`\nhandler will execute with the latest `EditorState` object based on those\nchanges.\n"
  },
  {
    "path": "docs/QuickStart-Rich-Styling.md",
    "content": "---\nid: quickstart-rich-styling\ntitle: Rich Styling\n---\n\nNow that we have established the basics of the top-level API, we can go a step\nfurther and examine how basic rich styling can be added to a `Draft` editor.\n\nA [rich text example](https://github.com/facebook/draft-js/tree/master/examples/draft-0-10-0/rich)\nis also available to follow along.\n\n## EditorState: Yours to Command\n\nThe previous article introduced the `EditorState` object as a snapshot of the full state of the editor, as provided by the `Editor` core via the `onChange` prop.\n\nHowever, since your top-level React component is responsible for maintaining the state, you also have the freedom to apply changes to that `EditorState` object in any way you see fit.\n\nFor inline and block style behavior, for example, the [`RichUtils`](/docs/api-reference-rich-utils) module provides a number of useful functions to help manipulate state.\n\nSimilarly, the [`Modifier`](/docs/api-reference-modifier) module also provides a\nnumber of common operations that allow you to apply edits, including changes\nto text, styles, and more. This module is a suite of edit functions that\ncompose simpler, smaller edit functions to return the desired `EditorState`\nobject.\n\nFor this example, we'll stick with `RichUtils` to demonstrate how to apply basic\nrich styling within the top-level component.\n\n## RichUtils and Key Commands\n\n`RichUtils` has information about the core key commands available to web editors,\nsuch as Cmd+B (bold), Cmd+I (italic), and so on.\n\nWe can observe and handle key commands via the `handleKeyCommand` prop, and\nhook these into `RichUtils` to apply or remove the desired style.\n\n```js\nimport {Editor, EditorState, RichUtils} from 'draft-js';\n\nclass MyEditor extends React.Component {\n  constructor(props) {\n    super(props);\n    this.state = {editorState: EditorState.createEmpty()};\n    this.onChange = editorState => this.setState({editorState});\n    this.handleKeyCommand = this.handleKeyCommand.bind(this);\n  }\n\n  handleKeyCommand(command, editorState) {\n    const newState = RichUtils.handleKeyCommand(editorState, command);\n\n    if (newState) {\n      this.onChange(newState);\n      return 'handled';\n    }\n\n    return 'not-handled';\n  }\n\n  render() {\n    return (\n      <Editor\n        editorState={this.state.editorState}\n        handleKeyCommand={this.handleKeyCommand}\n        onChange={this.onChange}\n      />\n    );\n  }\n}\n```\n\n> `handleKeyCommand`\n>\n> The `command` argument supplied to `handleKeyCommand` is a string value, the\n> name of the command to be executed. This is mapped from a DOM key event. The\n> `editorState` argument represents the latest editor state as it might be\n> changed internally by draft when handling the key. Use this instance of the\n> editor state inside `handleKeyCommand`. See\n> [Advanced Topics - Key Binding](/docs/advanced-topics-key-bindings) for more\n> on this, as well as details on why the function returns `handled` or `not-handled`.\n\n## Styling Controls in UI\n\nWithin your React component, you can add buttons or other controls to allow\nthe user to modify styles within the editor. In the example above, we are using\nknown key commands, but we can add more complex UI to provide these rich\nfeatures.\n\nHere's a super-basic example with a \"Bold\" button to toggle the `BOLD` style.\n\n```js\nclass MyEditor extends React.Component {\n  // ...\n\n  _onBoldClick() {\n    this.onChange(RichUtils.toggleInlineStyle(this.state.editorState, 'BOLD'));\n  }\n\n  render() {\n    return (\n      <div>\n        <button onClick={this._onBoldClick.bind(this)}>Bold</button>\n        <Editor\n          editorState={this.state.editorState}\n          handleKeyCommand={this.handleKeyCommand}\n          onChange={this.onChange}\n        />\n      </div>\n    );\n  }\n}\n```\n"
  },
  {
    "path": "examples/draft-0-10-0/color/color.html",
    "content": "<!--\nCopyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n\nThis file provided by Facebook is for non-commercial testing and evaluation\npurposes only. Facebook reserves all rights not expressly granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\nFACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n-->\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Draft • Color</title>\n    <link rel=\"stylesheet\" href=\"../../../dist/Draft.css\" />\n  </head>\n  <body>\n    <div style=\"font-family: Georgia, serif; font-size: 15px; padding: 20px; width: 600px; line-height: 24px;\">\n      This example demonstrates how custom inline styles can be used to create\n      editors with an unlimited range of style combinations. Note also that\n      the state of the editor can be manipulated to enforce that only one\n      color may be active at any time.\n    </div>\n    <div id=\"target\"></div>\n    <script src=\"../../../node_modules/react/umd/react.development.js\"></script>\n    <script src=\"../../../node_modules/react-dom/umd/react-dom.development.js\"></script>\n    <script src=\"../../../node_modules/immutable/dist/immutable.js\"></script>\n    <script src=\"../../../node_modules/es6-shim/es6-shim.js\"></script>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.js\"></script>\n    <script src=\"../../../dist/Draft.js\"></script>\n    <script type=\"text/babel\">\n      'use strict';\n\n      const {Editor, EditorState, Modifier, RichUtils} = Draft;\n\n      class ColorfulEditorExample extends React.Component {\n        constructor(props) {\n          super(props);\n          this.state = {editorState: EditorState.createEmpty()};\n\n          this.focus = () => this.editor.focus();\n          this.onChange = (editorState) => this.setState({editorState});\n          this.toggleColor = (toggledColor) => this._toggleColor(toggledColor);\n        }\n\n        _toggleColor(toggledColor) {\n          const {editorState} = this.state;\n          const selection = editorState.getSelection();\n\n          // Let's just allow one color at a time. Turn off all active colors.\n          const nextContentState = Object.keys(colorStyleMap)\n            .reduce((contentState, color) => {\n              return Modifier.removeInlineStyle(contentState, selection, color)\n            }, editorState.getCurrentContent());\n\n          let nextEditorState = EditorState.push(\n            editorState,\n            nextContentState,\n            'change-inline-style'\n          );\n\n          const currentStyle = editorState.getCurrentInlineStyle();\n\n          // Unset style override for current color.\n          if (selection.isCollapsed()) {\n            nextEditorState = currentStyle.reduce((state, color) => {\n              return RichUtils.toggleInlineStyle(state, color);\n            }, nextEditorState);\n          }\n\n          // If the color is being toggled on, apply it.\n          if (!currentStyle.has(toggledColor)) {\n            nextEditorState = RichUtils.toggleInlineStyle(\n              nextEditorState,\n              toggledColor\n            );\n          }\n\n          this.onChange(nextEditorState);\n        }\n\n        render() {\n          const {editorState} = this.state;\n          return (\n            <div style={styles.root}>\n              <ColorControls\n                editorState={editorState}\n                onToggle={this.toggleColor}\n              />\n              <div style={styles.editor} onClick={this.focus}>\n                <Editor\n                  customStyleMap={colorStyleMap}\n                  editorState={editorState}\n                  onChange={this.onChange}\n                  placeholder=\"Write something colorful...\"\n                  ref={(ref) => this.editor = ref}\n                />\n              </div>\n            </div>\n          );\n        }\n      }\n\n      class StyleButton extends React.Component {\n        constructor(props) {\n          super(props);\n          this.onToggle = (e) => {\n            e.preventDefault();\n            this.props.onToggle(this.props.style);\n          };\n        }\n\n        render() {\n          let style;\n          if (this.props.active) {\n            style = {...styles.styleButton, ...colorStyleMap[this.props.style]};\n          } else {\n            style = styles.styleButton;\n          }\n\n          return (\n            <span style={style} onMouseDown={this.onToggle}>\n              {this.props.label}\n            </span>\n          );\n        }\n      }\n\n      var COLORS = [\n        {label: 'Red', style: 'red'},\n        {label: 'Orange', style: 'orange'},\n        {label: 'Yellow', style: 'yellow'},\n        {label: 'Green', style: 'green'},\n        {label: 'Blue', style: 'blue'},\n        {label: 'Indigo', style: 'indigo'},\n        {label: 'Violet', style: 'violet'},\n      ];\n\n      const ColorControls = (props) => {\n        var currentStyle = props.editorState.getCurrentInlineStyle();\n        return (\n          <div style={styles.controls}>\n            {COLORS.map(type =>\n              <StyleButton\n                key={type.label}\n                active={currentStyle.has(type.style)}\n                label={type.label}\n                onToggle={props.onToggle}\n                style={type.style}\n              />\n            )}\n          </div>\n        );\n      };\n\n      // This object provides the styling information for our custom color\n      // styles.\n      const colorStyleMap = {\n        red: {\n          color: 'rgba(255, 0, 0, 1.0)',\n        },\n        orange: {\n          color: 'rgba(255, 127, 0, 1.0)',\n        },\n        yellow: {\n          color: 'rgba(180, 180, 0, 1.0)',\n        },\n        green: {\n          color: 'rgba(0, 180, 0, 1.0)',\n        },\n        blue: {\n          color: 'rgba(0, 0, 255, 1.0)',\n        },\n        indigo: {\n          color: 'rgba(75, 0, 130, 1.0)',\n        },\n        violet: {\n          color: 'rgba(127, 0, 255, 1.0)',\n        },\n      };\n\n      const styles = {\n        root: {\n          fontFamily: '\\'Georgia\\', serif',\n          fontSize: 14,\n          padding: 20,\n          width: 600,\n        },\n        editor: {\n          borderTop: '1px solid #ddd',\n          cursor: 'text',\n          fontSize: 16,\n          marginTop: 20,\n          minHeight: 400,\n          paddingTop: 20,\n        },\n        controls: {\n          fontFamily: '\\'Helvetica\\', sans-serif',\n          fontSize: 14,\n          marginBottom: 10,\n          userSelect: 'none',\n        },\n        styleButton: {\n          color: '#999',\n          cursor: 'pointer',\n          marginRight: 16,\n          padding: '2px 0',\n        },\n      };\n\n      ReactDOM.render(\n        <ColorfulEditorExample />,\n        document.getElementById('target')\n      );\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/draft-0-10-0/convertFromHTML/convert.html",
    "content": "<!--\nCopyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n\nThis file provided by Facebook is for non-commercial testing and evaluation\npurposes only. Facebook reserves all rights not expressly granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\nFACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n-->\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Draft • Convert from HTML</title>\n    <link rel=\"stylesheet\" href=\"../../../dist/Draft.css\" />\n  </head>\n  <body>\n    <div id=\"target\"></div>\n    <script src=\"../../../node_modules/react/umd/react.development.js\"></script>\n    <script src=\"../../../node_modules/react-dom/umd/react-dom.development.js\"></script>\n    <script src=\"../../../node_modules/immutable/dist/immutable.js\"></script>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.js\"></script>\n    <script src=\"../../../node_modules/es6-shim/es6-shim.js\"></script>\n    <script src=\"../../../dist/Draft.js\"></script>\n    <script type=\"text/babel\">\n      'use strict';\n\n      const {\n        CompositeDecorator,\n        ContentState,\n        Editor,\n        EditorState,\n        convertFromHTML,\n        convertToRaw,\n      } = Draft;\n\n      class HTMLConvertExample extends React.Component {\n        constructor(props) {\n          super(props);\n\n          const decorator = new CompositeDecorator([\n            {\n              strategy: findLinkEntities,\n              component: Link,\n            },\n            {\n              strategy: findImageEntities,\n              component: Image,\n            },\n          ]);\n\n          const sampleMarkup =\n            '<b>Bold text</b>, <i>Italic text</i><br/ ><br />' +\n            '<a href=\"http://www.facebook.com\">Example link</a><br /><br/ >' +\n            '<img src=\"image.png\" height=\"112\" width=\"200\" />';\n\n          const blocksFromHTML = convertFromHTML(sampleMarkup);\n          const state = ContentState.createFromBlockArray(\n            blocksFromHTML.contentBlocks,\n            blocksFromHTML.entityMap,\n          );\n\n          this.state = {\n            editorState: EditorState.createWithContent(\n              state,\n              decorator,\n            ),\n          };\n\n          this.focus = () => this.refs.editor.focus();\n          this.onChange = (editorState) => this.setState({editorState});\n          this.logState = () => {\n            const content = this.state.editorState.getCurrentContent();\n            console.log(convertToRaw(content));\n          };\n        }\n\n        render() {\n          return (\n            <div style={styles.root}>\n              <div style={{marginBottom: 10}}>\n                Sample HTML converted into Draft content state\n              </div>\n              <div style={styles.editor} onClick={this.focus}>\n                <Editor\n                  editorState={this.state.editorState}\n                  onChange={this.onChange}\n                  ref=\"editor\"\n                />\n              </div>\n              <input\n                onClick={this.logState}\n                style={styles.button}\n                type=\"button\"\n                value=\"Log State\"\n              />\n            </div>\n          );\n        }\n      }\n\n      function findLinkEntities(contentBlock, callback, contentState) {\n        contentBlock.findEntityRanges(\n          (character) => {\n            const entityKey = character.getEntity();\n            return (\n              entityKey !== null &&\n              contentState.getEntity(entityKey).getType() === 'LINK'\n            );\n          },\n          callback\n        );\n      }\n\n      const Link = (props) => {\n        const {url} = props.contentState.getEntity(props.entityKey).getData();\n        return (\n          <a href={url} style={styles.link}>\n            {props.children}\n          </a>\n        );\n      };\n\n      function findImageEntities(contentBlock, callback, contentState) {\n        contentBlock.findEntityRanges(\n          (character) => {\n            const entityKey = character.getEntity();\n            return (\n              entityKey !== null &&\n              contentState.getEntity(entityKey).getType() === 'IMAGE'\n            );\n          },\n          callback\n        );\n      }\n\n      const Image = (props) => {\n        const {\n          height,\n          src,\n          width,\n        } = props.contentState.getEntity(props.entityKey).getData();\n\n        return (\n          <img src={src} height={height} width={width} />\n        );\n      };\n\n      const styles = {\n        root: {\n          fontFamily: '\\'Helvetica\\', sans-serif',\n          padding: 20,\n          width: 600,\n        },\n        editor: {\n          border: '1px solid #ccc',\n          cursor: 'text',\n          minHeight: 80,\n          padding: 10,\n        },\n        button: {\n          marginTop: 10,\n          textAlign: 'center',\n        },\n      };\n\n      ReactDOM.render(\n        <HTMLConvertExample />,\n        document.getElementById('target')\n      );\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/draft-0-10-0/entity/entity.html",
    "content": "<!--\nCopyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n\nThis file provided by Facebook is for non-commercial testing and evaluation\npurposes only. Facebook reserves all rights not expressly granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\nFACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n-->\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Draft • Entity Editor</title>\n    <link rel=\"stylesheet\" href=\"../../../dist/Draft.css\" />\n  </head>\n  <body>\n    <div id=\"target\"></div>\n    <script src=\"../../../node_modules/react/umd/react.development.js\"></script>\n    <script src=\"../../../node_modules/react-dom/umd/react-dom.development.js\"></script>\n    <script src=\"../../../node_modules/immutable/dist/immutable.js\"></script>\n    <script src=\"../../../node_modules/es6-shim/es6-shim.js\"></script>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.js\"></script>\n    <script src=\"../../../dist/Draft.js\"></script>\n    <script type=\"text/babel\">\n      'use strict';\n\n      const {\n        convertFromRaw,\n        convertToRaw,\n        CompositeDecorator,\n        Editor,\n        EditorState,\n      } = Draft;\n\n      const rawContent = {\n        blocks: [\n          {\n            text: (\n              'This is an \"immutable\" entity: Superman. Deleting any ' +\n              'characters will delete the entire entity. Adding characters ' +\n              'will remove the entity from the range.'\n            ),\n            type: 'unstyled',\n            entityRanges: [{offset: 31, length: 8, key: 'first'}],\n          },\n          {\n            text: '',\n            type: 'unstyled',\n          },\n          {\n            text: (\n              'This is a \"mutable\" entity: Batman. Characters may be added ' +\n              'and removed.'\n            ),\n            type: 'unstyled',\n            entityRanges: [{offset: 28, length: 6, key: 'second'}],\n          },\n          {\n            text: '',\n            type: 'unstyled',\n          },\n          {\n            text: (\n              'This is a \"segmented\" entity: Green Lantern. Deleting any ' +\n              'characters will delete the current \"segment\" from the range. ' +\n              'Adding characters will remove the entire entity from the range.'\n            ),\n            type: 'unstyled',\n            entityRanges: [{offset: 30, length: 13, key: 'third'}],\n          },\n        ],\n\n        entityMap: {\n          first: {\n            type: 'TOKEN',\n            mutability: 'IMMUTABLE',\n          },\n          second: {\n            type: 'TOKEN',\n            mutability: 'MUTABLE',\n          },\n          third: {\n            type: 'TOKEN',\n            mutability: 'SEGMENTED',\n          },\n        },\n      };\n\n      class EntityEditorExample extends React.Component {\n        constructor(props) {\n          super(props);\n\n          const decorator = new CompositeDecorator([\n            {\n              strategy: getEntityStrategy('IMMUTABLE'),\n              component: TokenSpan,\n            },\n            {\n              strategy: getEntityStrategy('MUTABLE'),\n              component: TokenSpan,\n            },\n            {\n              strategy: getEntityStrategy('SEGMENTED'),\n              component: TokenSpan,\n            },\n          ]);\n\n          const blocks = convertFromRaw(rawContent);\n\n          this.state = {\n            editorState: EditorState.createWithContent(blocks, decorator),\n          };\n\n          this.focus = () => this.refs.editor.focus();\n          this.onChange = (editorState) => this.setState({editorState});\n          this.logState = () => {\n            const content = this.state.editorState.getCurrentContent();\n            console.log(convertToRaw(content));\n          };\n        }\n\n        render() {\n          return (\n            <div style={styles.root}>\n              <div style={styles.editor} onClick={this.focus}>\n                <Editor\n                  editorState={this.state.editorState}\n                  onChange={this.onChange}\n                  placeholder=\"Enter some text...\"\n                  ref=\"editor\"\n                />\n              </div>\n              <input\n                onClick={this.logState}\n                style={styles.button}\n                type=\"button\"\n                value=\"Log State\"\n              />\n            </div>\n          );\n        }\n      }\n\n      function getEntityStrategy(mutability) {\n        return function(contentBlock, callback, contentState) {\n          contentBlock.findEntityRanges(\n            (character) => {\n              const entityKey = character.getEntity();\n              if (entityKey === null) {\n                return false;\n              }\n              return contentState.getEntity(entityKey).getMutability() === mutability;\n            },\n            callback\n          );\n        };\n      }\n\n      function getDecoratedStyle(mutability) {\n        switch (mutability) {\n          case 'IMMUTABLE': return styles.immutable;\n          case 'MUTABLE': return styles.mutable;\n          case 'SEGMENTED': return styles.segmented;\n          default: return null;\n        }\n      }\n\n      const TokenSpan = (props) => {\n        const style = getDecoratedStyle(\n          props.contentState.getEntity(props.entityKey).getMutability()\n        );\n        return (\n          <span data-offset-key={props.offsetkey} style={style}>\n            {props.children}\n          </span>\n        );\n      };\n\n      const styles = {\n        root: {\n          fontFamily: '\\'Helvetica\\', sans-serif',\n          padding: 20,\n          width: 600,\n        },\n        editor: {\n          border: '1px solid #ccc',\n          cursor: 'text',\n          minHeight: 80,\n          padding: 10,\n        },\n        button: {\n          marginTop: 10,\n          textAlign: 'center',\n        },\n        immutable: {\n          backgroundColor: 'rgba(0, 0, 0, 0.2)',\n          padding: '2px 0',\n        },\n        mutable: {\n          backgroundColor: 'rgba(204, 204, 255, 1.0)',\n          padding: '2px 0',\n        },\n        segmented: {\n          backgroundColor: 'rgba(248, 222, 126, 1.0)',\n          padding: '2px 0',\n        },\n      };\n\n      ReactDOM.render(\n        <EntityEditorExample />,\n        document.getElementById('target')\n      );\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/draft-0-10-0/iframe/iframe.html",
    "content": "<!--\nCopyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n\nThis file provided by Facebook is for non-commercial testing and evaluation\npurposes only. Facebook reserves all rights not expressly granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\nFACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n-->\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Draft • Iframed Editor</title>\n  </head>\n  <body>\n    <div id=\"target\"></div>\n    <script src=\"../../../node_modules/react/umd/react.development.js\"></script>\n    <script src=\"../../../node_modules/react-dom/umd/react-dom.development.js\"></script>\n    <script src=\"../../../node_modules/immutable/dist/immutable.js\"></script>\n    <script src=\"../../../node_modules/es6-shim/es6-shim.js\"></script>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.js\"></script>\n    <script src=\"../../../dist/Draft.js\"></script>\n    <script type=\"text/babel\">\n      'use strict';\n\n      const {Editor, EditorState, RichUtils, getDefaultKeyBinding} = Draft;\n\n      class IframedEditorExample extends React.Component {\n        constructor(props) {\n          super(props);\n          this.state = {editorState: EditorState.createEmpty()};\n\n          this.focus = () => this.refs.editor.focus();\n          this.onChange = (editorState) => this.setState({editorState});\n\n          this.handleKeyCommand = this._handleKeyCommand.bind(this);\n          this.mapKeyToEditorCommand = this._mapKeyToEditorCommand.bind(this);\n          this.toggleBlockType = this._toggleBlockType.bind(this);\n          this.toggleInlineStyle = this._toggleInlineStyle.bind(this);\n        }\n\n        _handleKeyCommand(command, editorState) {\n          const newState = RichUtils.handleKeyCommand(editorState, command);\n          if (newState) {\n            this.onChange(newState);\n            return true;\n          }\n          return false;\n        }\n\n        _mapKeyToEditorCommand(e) {\n          if (e.keyCode === 9 /* TAB */) {\n            const newEditorState = RichUtils.onTab(\n              e,\n              this.state.editorState,\n              4, /* maxDepth */\n            );\n            if (newEditorState !== this.state.editorState) {\n              this.onChange(newEditorState);\n            }\n            return;\n          }\n          return getDefaultKeyBinding(e);\n        }\n\n        _toggleBlockType(blockType) {\n          this.onChange(\n            RichUtils.toggleBlockType(\n              this.state.editorState,\n              blockType\n            )\n          );\n        }\n\n        _toggleInlineStyle(inlineStyle) {\n          this.onChange(\n            RichUtils.toggleInlineStyle(\n              this.state.editorState,\n              inlineStyle\n            )\n          );\n        }\n\n        render() {\n          const {editorState} = this.state;\n\n          // If the user changes block type before entering any text, we can\n          // either style the placeholder or hide it. Let's just hide it now.\n          let className = 'RichEditor-editor';\n          var contentState = editorState.getCurrentContent();\n          if (!contentState.hasText()) {\n            if (contentState.getBlockMap().first().getType() !== 'unstyled') {\n              className += ' RichEditor-hidePlaceholder';\n            }\n          }\n\n          return (\n            <Frame\n              head={`\n                  <meta charset=\"utf-8\" />\n                  <link rel=\"stylesheet\" href=\"../../../dist/Draft.css\" />\n                  <link rel=\"stylesheet\" href=\"../rich/RichEditor.css\" />\n              `}>\n              <div className=\"Editor-root\">\n                <BlockStyleControls\n                  editorState={editorState}\n                  onToggle={this.toggleBlockType}\n                />\n                <InlineStyleControls\n                  editorState={editorState}\n                  onToggle={this.toggleInlineStyle}\n                />\n                <div className={className} onClick={this.focus}>\n                  <Editor\n                    blockStyleFn={getBlockStyle}\n                    customStyleMap={styleMap}\n                    editorState={editorState}\n                    handleKeyCommand={this.handleKeyCommand}\n                    keyBindingFn={this.mapKeyToEditorCommand}\n                    onChange={this.onChange}\n                    placeholder=\"Tell a story...\"\n                    ref=\"editor\"\n                    spellCheck={true}\n                  />\n                </div>\n              </div>\n            </Frame>\n          );\n        }\n      }\n\n      class Frame extends React.Component {\n        constructor(props) {\n          super(props);\n          this.iframeRef = null;\n          this.handleRef = this._handleRef.bind(this);\n        }\n\n        _handleRef(ref) {\n          if (ref !== this.iframeRef) {\n            this.iframeRef = ref;\n            if (ref) {\n              if (ref.contentDocument && this.props.head) {\n                ref.contentDocument.head.innerHTML = this.props.head;\n              }\n              // Re-render must take place in the next tick (Firefox)\n              setTimeout(() => {\n                this.forceUpdate();\n              });\n            }\n          }\n        }\n\n        render() {\n          const ref = this.iframeRef;\n          let portal = null;\n          if (ref && ref.contentDocument) {\n            portal = ReactDOM.createPortal(\n              React.cloneElement(this.props.children, { reference: ref }),\n              ref.contentDocument.body\n            );\n          }\n          return (\n            <div>\n              <iframe ref={this.handleRef} style={styles.frame} />\n              {portal}\n            </div>\n          );\n        }\n      }\n\n\n      // Custom overrides for \"code\" style.\n      const styleMap = {\n        CODE: {\n          backgroundColor: 'rgba(0, 0, 0, 0.05)',\n          fontFamily: '\"Inconsolata\", \"Menlo\", \"Consolas\", monospace',\n          fontSize: 16,\n          padding: 2,\n        },\n      };\n\n      function getBlockStyle(block) {\n        switch (block.getType()) {\n          case 'blockquote': return 'RichEditor-blockquote';\n          default: return null;\n        }\n      }\n\n      class StyleButton extends React.Component {\n        constructor() {\n          super();\n          this.onToggle = (e) => {\n            e.preventDefault();\n            this.props.onToggle(this.props.style);\n          };\n        }\n\n        render() {\n          let className = 'RichEditor-styleButton';\n          if (this.props.active) {\n            className += ' RichEditor-activeButton';\n          }\n\n          return (\n            <span className={className} onMouseDown={this.onToggle}>\n              {this.props.label}\n            </span>\n          );\n        }\n      }\n\n      const BLOCK_TYPES = [\n        {label: 'H1', style: 'header-one'},\n        {label: 'H2', style: 'header-two'},\n        {label: 'H3', style: 'header-three'},\n        {label: 'H4', style: 'header-four'},\n        {label: 'H5', style: 'header-five'},\n        {label: 'H6', style: 'header-six'},\n        {label: 'Blockquote', style: 'blockquote'},\n        {label: 'UL', style: 'unordered-list-item'},\n        {label: 'OL', style: 'ordered-list-item'},\n        {label: 'Code Block', style: 'code-block'},\n      ];\n\n      const BlockStyleControls = (props) => {\n        const {editorState} = props;\n        const selection = editorState.getSelection();\n        const blockType = editorState\n          .getCurrentContent()\n          .getBlockForKey(selection.getStartKey())\n          .getType();\n\n        return (\n          <div className=\"RichEditor-controls\">\n            {BLOCK_TYPES.map((type) =>\n              <StyleButton\n                key={type.label}\n                active={type.style === blockType}\n                label={type.label}\n                onToggle={props.onToggle}\n                style={type.style}\n              />\n            )}\n          </div>\n        );\n      };\n\n      var INLINE_STYLES = [\n        {label: 'Bold', style: 'BOLD'},\n        {label: 'Italic', style: 'ITALIC'},\n        {label: 'Underline', style: 'UNDERLINE'},\n        {label: 'Monospace', style: 'CODE'},\n      ];\n\n      const InlineStyleControls = (props) => {\n        const currentStyle = props.editorState.getCurrentInlineStyle();\n        \n        return (\n          <div className=\"RichEditor-controls\">\n            {INLINE_STYLES.map((type) =>\n              <StyleButton\n                key={type.label}\n                active={currentStyle.has(type.style)}\n                label={type.label}\n                onToggle={props.onToggle}\n                style={type.style}\n              />\n            )}\n          </div>\n        );\n      };\n\n      const styles = {\n        frame: {\n          height: 400,\n          width: 800,\n        },\n      };\n\n      ReactDOM.render(\n        <IframedEditorExample />,\n        document.getElementById('target')\n      );\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/draft-0-10-0/link/link.html",
    "content": "<!--\nCopyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n\nThis file provided by Facebook is for non-commercial testing and evaluation\npurposes only. Facebook reserves all rights not expressly granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\nFACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n-->\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Draft • Link Editor</title>\n    <link rel=\"stylesheet\" href=\"../../../dist/Draft.css\" />\n  </head>\n  <body>\n    <div id=\"target\"></div>\n    <script src=\"../../../node_modules/react/umd/react.development.js\"></script>\n    <script src=\"../../../node_modules/react-dom/umd/react-dom.development.js\"></script>\n    <script src=\"../../../node_modules/immutable/dist/immutable.js\"></script>\n    <script src=\"../../../node_modules/es6-shim/es6-shim.js\"></script>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.js\"></script>\n    <script src=\"../../../dist/Draft.js\"></script>\n    <script type=\"text/babel\">\n      'use strict';\n\n      const {\n        convertToRaw,\n        CompositeDecorator,\n        Editor,\n        EditorState,\n        RichUtils,\n      } = Draft;\n\n      class LinkEditorExample extends React.Component {\n        constructor(props) {\n          super(props);\n\n          const decorator = new CompositeDecorator([\n            {\n              strategy: findLinkEntities,\n              component: Link,\n            },\n          ]);\n\n          this.state = {\n            editorState: EditorState.createEmpty(decorator),\n            showURLInput: false,\n            urlValue: '',\n          };\n\n          this.focus = () => this.refs.editor.focus();\n          this.onChange = (editorState) => this.setState({editorState});\n          this.logState = () => {\n            const content = this.state.editorState.getCurrentContent();\n            console.log(convertToRaw(content));\n          };\n\n          this.promptForLink = this._promptForLink.bind(this);\n          this.onURLChange = (e) => this.setState({urlValue: e.target.value});\n          this.confirmLink = this._confirmLink.bind(this);\n          this.onLinkInputKeyDown = this._onLinkInputKeyDown.bind(this);\n          this.removeLink = this._removeLink.bind(this);\n        }\n\n        _promptForLink(e) {\n          e.preventDefault();\n          const {editorState} = this.state;\n          const selection = editorState.getSelection();\n          if (!selection.isCollapsed()) {\n            const contentState = editorState.getCurrentContent();\n            const startKey = editorState.getSelection().getStartKey();\n            const startOffset = editorState.getSelection().getStartOffset();\n            const blockWithLinkAtBeginning = contentState.getBlockForKey(startKey);\n            const linkKey = blockWithLinkAtBeginning.getEntityAt(startOffset);\n\n            let url = '';\n            if (linkKey) {\n              const linkInstance = contentState.getEntity(linkKey);\n              url = linkInstance.getData().url;\n            }\n\n            this.setState({\n              showURLInput: true,\n              urlValue: url,\n            }, () => {\n              setTimeout(() => this.refs.url.focus(), 0);\n            });\n          }\n        }\n\n        _confirmLink(e) {\n          e.preventDefault();\n          const {editorState, urlValue} = this.state;\n          const contentState = editorState.getCurrentContent();\n          const contentStateWithEntity = contentState.createEntity(\n            'LINK',\n            'MUTABLE',\n            {url: urlValue}\n          );\n          const entityKey = contentStateWithEntity.getLastCreatedEntityKey();\n          const newEditorState = EditorState.set(editorState, { currentContent: contentStateWithEntity });\n          this.setState({\n            editorState: RichUtils.toggleLink(\n              newEditorState,\n              newEditorState.getSelection(),\n              entityKey\n            ),\n            showURLInput: false,\n            urlValue: '',\n          }, () => {\n            setTimeout(() => this.refs.editor.focus(), 0);\n          });\n        }\n\n        _onLinkInputKeyDown(e) {\n          if (e.which === 13) {\n            this._confirmLink(e);\n          }\n        }\n\n        _removeLink(e) {\n          e.preventDefault();\n          const {editorState} = this.state;\n          const selection = editorState.getSelection();\n          if (!selection.isCollapsed()) {\n            this.setState({\n              editorState: RichUtils.toggleLink(editorState, selection, null),\n            });\n          }\n        }\n\n        render() {\n          let urlInput;\n          if (this.state.showURLInput) {\n            urlInput =\n              <div style={styles.urlInputContainer}>\n                <input\n                  onChange={this.onURLChange}\n                  ref=\"url\"\n                  style={styles.urlInput}\n                  type=\"text\"\n                  value={this.state.urlValue}\n                  onKeyDown={this.onLinkInputKeyDown}\n                />\n                <button onMouseDown={this.confirmLink}>\n                  Confirm\n                </button>\n              </div>;\n          }\n\n          return (\n            <div style={styles.root}>\n              <div style={{marginBottom: 10}}>\n                Select some text, then use the buttons to add or remove links\n                on the selected text.\n              </div>\n              <div style={styles.buttons}>\n                <button\n                  onMouseDown={this.promptForLink}\n                  style={{marginRight: 10}}>\n                  Add Link\n                </button>\n                <button onMouseDown={this.removeLink}>\n                  Remove Link\n                </button>\n              </div>\n              {urlInput}\n              <div style={styles.editor} onClick={this.focus}>\n                <Editor\n                  editorState={this.state.editorState}\n                  onChange={this.onChange}\n                  placeholder=\"Enter some text...\"\n                  ref=\"editor\"\n                />\n              </div>\n              <input\n                onClick={this.logState}\n                style={styles.button}\n                type=\"button\"\n                value=\"Log State\"\n              />\n            </div>\n          );\n        }\n      }\n\n      function findLinkEntities(contentBlock, callback, contentState) {\n        contentBlock.findEntityRanges(\n          (character) => {\n            const entityKey = character.getEntity();\n            return (\n              entityKey !== null &&\n              contentState.getEntity(entityKey).getType() === 'LINK'\n            );\n          },\n          callback\n        );\n      }\n\n      const Link = (props) => {\n        const {url} = props.contentState.getEntity(props.entityKey).getData();\n        return (\n          <a href={url} style={styles.link}>\n            {props.children}\n          </a>\n        );\n      };\n\n      const styles = {\n        root: {\n          fontFamily: '\\'Georgia\\', serif',\n          padding: 20,\n          width: 600,\n        },\n        buttons: {\n          marginBottom: 10,\n        },\n        urlInputContainer: {\n          marginBottom: 10,\n        },\n        urlInput: {\n          fontFamily: '\\'Georgia\\', serif',\n          marginRight: 10,\n          padding: 3,\n        },\n        editor: {\n          border: '1px solid #ccc',\n          cursor: 'text',\n          minHeight: 80,\n          padding: 10,\n        },\n        button: {\n          marginTop: 10,\n          textAlign: 'center',\n        },\n        link: {\n          color: '#3b5998',\n          textDecoration: 'underline',\n        },\n      };\n\n      ReactDOM.render(\n        <LinkEditorExample />,\n        document.getElementById('target')\n      );\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/draft-0-10-0/media/media.html",
    "content": "<!--\nCopyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n\nThis file provided by Facebook is for non-commercial testing and evaluation\npurposes only. Facebook reserves all rights not expressly granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\nFACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n-->\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Draft • Media Editor</title>\n    <link rel=\"stylesheet\" href=\"../../../dist/Draft.css\" />\n  </head>\n  <body>\n    <div id=\"target\"></div>\n    <script src=\"../../../node_modules/react/umd/react.development.js\"></script>\n    <script src=\"../../../node_modules/react-dom/umd/react-dom.development.js\"></script>\n    <script src=\"../../../node_modules/immutable/dist/immutable.js\"></script>\n    <script src=\"../../../node_modules/es6-shim/es6-shim.js\"></script>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.js\"></script>\n    <script src=\"../../../dist/Draft.js\"></script>\n    <script type=\"text/babel\">\n      'use strict';\n\n      const {\n        AtomicBlockUtils,\n        Editor,\n        EditorState,\n        RichUtils,\n        convertToRaw,\n      } = Draft;\n\n      class MediaEditorExample extends React.Component {\n        constructor(props) {\n          super(props);\n\n          this.state = {\n            editorState: EditorState.createEmpty(),\n            showURLInput: false,\n            url: '',\n            urlType: '',\n          };\n\n          this.focus = () => this.refs.editor.focus();\n          this.logState = () => {\n            const content = this.state.editorState.getCurrentContent();\n            console.log(convertToRaw(content));\n          };\n          this.onChange = (editorState) => this.setState({editorState});\n          this.onURLChange = (e) => this.setState({urlValue: e.target.value});\n\n          this.addAudio = this._addAudio.bind(this);\n          this.addImage = this._addImage.bind(this);\n          this.addVideo = this._addVideo.bind(this);\n          this.confirmMedia = this._confirmMedia.bind(this);\n          this.handleKeyCommand = this._handleKeyCommand.bind(this);\n          this.onURLInputKeyDown = this._onURLInputKeyDown.bind(this);\n        }\n\n        _handleKeyCommand(command, editorState) {\n          const newState = RichUtils.handleKeyCommand(editorState, command);\n          if (newState) {\n            this.onChange(newState);\n            return true;\n          }\n          return false;\n        }\n\n        _confirmMedia(e) {\n          e.preventDefault();\n          const {editorState, urlValue, urlType} = this.state;\n          const contentState = editorState.getCurrentContent();\n          const contentStateWithEntity = contentState.createEntity(\n            urlType,\n            'IMMUTABLE',\n            {src: urlValue}\n          );\n          const entityKey = contentStateWithEntity.getLastCreatedEntityKey();\n          const newEditorState = EditorState.set(\n            editorState,\n            {currentContent: contentStateWithEntity}\n          );\n\n          this.setState({\n            // The third parameter here is a space string, not an empty string\n            // If you set an empty string, you will get an error: Unknown DraftEntity key: null\n            editorState: AtomicBlockUtils.insertAtomicBlock(\n              newEditorState,\n              entityKey,\n              ' '\n            ),\n            showURLInput: false,\n            urlValue: '',\n          }, () => {\n            setTimeout(() => this.focus(), 0);\n          });\n        }\n\n        _onURLInputKeyDown(e) {\n          if (e.which === 13) {\n            this._confirmMedia(e);\n          }\n        }\n\n        _promptForMedia(type) {\n          this.setState({\n            showURLInput: true,\n            urlValue: '',\n            urlType: type,\n          }, () => {\n            setTimeout(() => this.refs.url.focus(), 0);\n          });\n        }\n\n        _addAudio() {\n          this._promptForMedia('audio');\n        }\n\n        _addImage() {\n          this._promptForMedia('image');\n        }\n\n        _addVideo() {\n          this._promptForMedia('video');\n        }\n\n        render() {\n          let urlInput;\n          if (this.state.showURLInput) {\n            urlInput =\n              <div style={styles.urlInputContainer}>\n                <input\n                  onChange={this.onURLChange}\n                  ref=\"url\"\n                  style={styles.urlInput}\n                  type=\"text\"\n                  value={this.state.urlValue}\n                  onKeyDown={this.onURLInputKeyDown}\n                />\n                <button onMouseDown={this.confirmMedia}>\n                  Confirm\n                </button>\n              </div>;\n          }\n\n          return (\n            <div style={styles.root}>\n              <div style={{marginBottom: 10}}>\n                Use the buttons to add audio, image, or video.\n              </div>\n              <div style={{marginBottom: 10}}>\n                Here are some local examples that can be entered as a URL:\n                <ul>\n                  <li>media.mp3</li>\n                  <li>media.png</li>\n                  <li>media.mp4</li>\n                </ul>\n              </div>\n              <div style={styles.buttons}>\n                <button onMouseDown={this.addAudio} style={{marginRight: 10}}>\n                  Add Audio\n                </button>\n                <button onMouseDown={this.addImage} style={{marginRight: 10}}>\n                  Add Image\n                </button>\n                <button onMouseDown={this.addVideo} style={{marginRight: 10}}>\n                  Add Video\n                </button>\n              </div>\n              {urlInput}\n              <div style={styles.editor} onClick={this.focus}>\n                <Editor\n                  blockRendererFn={mediaBlockRenderer}\n                  editorState={this.state.editorState}\n                  handleKeyCommand={this.handleKeyCommand}\n                  onChange={this.onChange}\n                  placeholder=\"Enter some text...\"\n                  ref=\"editor\"\n                />\n              </div>\n              <input\n                onClick={this.logState}\n                style={styles.button}\n                type=\"button\"\n                value=\"Log State\"\n              />\n            </div>\n          );\n        }\n      }\n\n      function mediaBlockRenderer(block) {\n        if (block.getType() === 'atomic') {\n          return {\n            component: Media,\n            editable: false,\n          };\n        }\n\n        return null;\n      }\n\n      const Audio = (props) => {\n        return <audio controls src={props.src} style={styles.media} />;\n      };\n\n      const Image = (props) => {\n        return <img src={props.src} style={styles.media} />;\n      };\n\n      const Video = (props) => {\n        return <video controls src={props.src} style={styles.media} />;\n      };\n\n      const Media = (props) => {\n        const entity = props.contentState.getEntity(\n          props.block.getEntityAt(0)\n        );\n        const {src} = entity.getData();\n        const type = entity.getType();\n\n        let media;\n        if (type === 'audio') {\n          media = <Audio src={src} />;\n        } else if (type === 'image') {\n          media = <Image src={src} />;\n        } else if (type === 'video') {\n          media = <Video src={src} />;\n        }\n\n        return media;\n      };\n\n      const styles = {\n        root: {\n          fontFamily: '\\'Georgia\\', serif',\n          padding: 20,\n          width: 600,\n        },\n        buttons: {\n          marginBottom: 10,\n        },\n        urlInputContainer: {\n          marginBottom: 10,\n        },\n        urlInput: {\n          fontFamily: '\\'Georgia\\', serif',\n          marginRight: 10,\n          padding: 3,\n        },\n        editor: {\n          border: '1px solid #ccc',\n          cursor: 'text',\n          minHeight: 80,\n          padding: 10,\n        },\n        button: {\n          marginTop: 10,\n          textAlign: 'center',\n        },\n        media: {\n          width: '100%',\n          // Fix an issue with Firefox rendering video controls\n          // with 'pre-wrap' white-space\n          whiteSpace: 'initial'\n        },\n      };\n\n      ReactDOM.render(\n        <MediaEditorExample />,\n        document.getElementById('target')\n      );\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/draft-0-10-0/plaintext/plaintext.html",
    "content": "<!--\nCopyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n\nThis file provided by Facebook is for non-commercial testing and evaluation\npurposes only. Facebook reserves all rights not expressly granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\nFACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n-->\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Draft • Plain Text Editor</title>\n    <link rel=\"stylesheet\" href=\"../../../dist/Draft.css\" />\n  </head>\n  <body>\n    <div id=\"target\"></div>\n    <script src=\"../../../node_modules/react/umd/react.development.js\"></script>\n    <script src=\"../../../node_modules/react-dom/umd/react-dom.development.js\"></script>\n    <script src=\"../../../node_modules/immutable/dist/immutable.js\"></script>\n    <script src=\"../../../node_modules/es6-shim/es6-shim.js\"></script>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.js\"></script>\n    <script src=\"../../../dist/Draft.js\"></script>\n    <script type=\"text/babel\">\n      'use strict';\n\n      const {Editor, EditorState} = Draft;\n\n      class PlainTextEditorExample extends React.Component {\n        constructor(props) {\n          super(props);\n          this.state = {editorState: EditorState.createEmpty()};\n          this.onChange = (editorState) => this.setState({editorState});\n          this.logState = () => console.log(this.state.editorState.toJS());\n          this.setDomEditorRef = ref => this.domEditor = ref;\n          this.focus = () => this.domEditor.focus();\n        }\n                \n        componentDidMount(){\n          this.domEditor.focus()\n        }\n        \n        render() {\n          return (\n            <div style={styles.root}>\n              <div style={styles.editor} onClick={this.focus}>\n                <Editor\n                  editorState={this.state.editorState}\n                  onChange={this.onChange}\n                  placeholder=\"Enter some text...\"\n                  ref={this.setDomEditorRef}\n                />\n              </div>\n              <input\n                onClick={this.logState}\n                style={styles.button}\n                type=\"button\"\n                value=\"Log State\"\n              />\n            </div>\n          );\n        }\n      }\n\n      const styles = {\n        root: {\n          fontFamily: '\\'Helvetica\\', sans-serif',\n          padding: 20,\n          width: 600,\n        },\n        editor: {\n          border: '1px solid #ccc',\n          cursor: 'text',\n          minHeight: 80,\n          padding: 10,\n        },\n        button: {\n          marginTop: 10,\n          textAlign: 'center',\n        },\n      };\n\n      ReactDOM.render(\n        <PlainTextEditorExample />,\n        document.getElementById('target')\n      );\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/draft-0-10-0/playground/README.md",
    "content": "This project was bootstrapped with [Create React App](https://github.com/facebookincubator/create-react-app).\n\nBelow you will find some information on how to perform common tasks.<br>\nYou can find the most recent version of this guide [here](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md).\n\n## Table of Contents\n\n- [Updating to New Releases](#updating-to-new-releases)\n- [Sending Feedback](#sending-feedback)\n- [Folder Structure](#folder-structure)\n- [Available Scripts](#available-scripts)\n  - [npm start](#npm-start)\n  - [npm test](#npm-test)\n  - [npm run build](#npm-run-build)\n  - [npm run eject](#npm-run-eject)\n- [Supported Language Features and Polyfills](#supported-language-features-and-polyfills)\n- [Syntax Highlighting in the Editor](#syntax-highlighting-in-the-editor)\n- [Displaying Lint Output in the Editor](#displaying-lint-output-in-the-editor)\n- [Debugging in the Editor](#debugging-in-the-editor)\n- [Formatting Code Automatically](#formatting-code-automatically)\n- [Changing the Page `<title>`](#changing-the-page-title)\n- [Installing a Dependency](#installing-a-dependency)\n- [Importing a Component](#importing-a-component)\n- [Code Splitting](#code-splitting)\n- [Adding a Stylesheet](#adding-a-stylesheet)\n- [Post-Processing CSS](#post-processing-css)\n- [Adding a CSS Preprocessor (Sass, Less etc.)](#adding-a-css-preprocessor-sass-less-etc)\n- [Adding Images, Fonts, and Files](#adding-images-fonts-and-files)\n- [Using the `public` Folder](#using-the-public-folder)\n  - [Changing the HTML](#changing-the-html)\n  - [Adding Assets Outside of the Module System](#adding-assets-outside-of-the-module-system)\n  - [When to Use the `public` Folder](#when-to-use-the-public-folder)\n- [Using Global Variables](#using-global-variables)\n- [Adding Bootstrap](#adding-bootstrap)\n  - [Using a Custom Theme](#using-a-custom-theme)\n- [Adding Flow](#adding-flow)\n- [Adding Custom Environment Variables](#adding-custom-environment-variables)\n  - [Referencing Environment Variables in the HTML](#referencing-environment-variables-in-the-html)\n  - [Adding Temporary Environment Variables In Your Shell](#adding-temporary-environment-variables-in-your-shell)\n  - [Adding Development Environment Variables In `.env`](#adding-development-environment-variables-in-env)\n- [Can I Use Decorators?](#can-i-use-decorators)\n- [Integrating with an API Backend](#integrating-with-an-api-backend)\n  - [Node](#node)\n  - [Ruby on Rails](#ruby-on-rails)\n- [Proxying API Requests in Development](#proxying-api-requests-in-development)\n  - [\"Invalid Host Header\" Errors After Configuring Proxy](#invalid-host-header-errors-after-configuring-proxy)\n  - [Configuring the Proxy Manually](#configuring-the-proxy-manually)\n  - [Configuring a WebSocket Proxy](#configuring-a-websocket-proxy)\n- [Using HTTPS in Development](#using-https-in-development)\n- [Generating Dynamic `<meta>` Tags on the Server](#generating-dynamic-meta-tags-on-the-server)\n- [Pre-Rendering into Static HTML Files](#pre-rendering-into-static-html-files)\n- [Injecting Data from the Server into the Page](#injecting-data-from-the-server-into-the-page)\n- [Running Tests](#running-tests)\n  - [Filename Conventions](#filename-conventions)\n  - [Command Line Interface](#command-line-interface)\n  - [Version Control Integration](#version-control-integration)\n  - [Writing Tests](#writing-tests)\n  - [Testing Components](#testing-components)\n  - [Using Third Party Assertion Libraries](#using-third-party-assertion-libraries)\n  - [Initializing Test Environment](#initializing-test-environment)\n  - [Focusing and Excluding Tests](#focusing-and-excluding-tests)\n  - [Coverage Reporting](#coverage-reporting)\n  - [Continuous Integration](#continuous-integration)\n  - [Disabling jsdom](#disabling-jsdom)\n  - [Snapshot Testing](#snapshot-testing)\n  - [Editor Integration](#editor-integration)\n- [Developing Components in Isolation](#developing-components-in-isolation)\n  - [Getting Started with Storybook](#getting-started-with-storybook)\n  - [Getting Started with Styleguidist](#getting-started-with-styleguidist)\n- [Making a Progressive Web App](#making-a-progressive-web-app)\n  - [Opting Out of Caching](#opting-out-of-caching)\n  - [Offline-First Considerations](#offline-first-considerations)\n  - [Progressive Web App Metadata](#progressive-web-app-metadata)\n- [Analyzing the Bundle Size](#analyzing-the-bundle-size)\n- [Deployment](#deployment)\n  - [Static Server](#static-server)\n  - [Other Solutions](#other-solutions)\n  - [Serving Apps with Client-Side Routing](#serving-apps-with-client-side-routing)\n  - [Building for Relative Paths](#building-for-relative-paths)\n  - [Azure](#azure)\n  - [Firebase](#firebase)\n  - [GitHub Pages](#github-pages)\n  - [Heroku](#heroku)\n  - [Netlify](#netlify)\n  - [Now](#now)\n  - [S3 and CloudFront](#s3-and-cloudfront)\n  - [Surge](#surge)\n- [Advanced Configuration](#advanced-configuration)\n- [Troubleshooting](#troubleshooting)\n  - [`npm start` doesn’t detect changes](#npm-start-doesnt-detect-changes)\n  - [`npm test` hangs on macOS Sierra](#npm-test-hangs-on-macos-sierra)\n  - [`npm run build` exits too early](#npm-run-build-exits-too-early)\n  - [`npm run build` fails on Heroku](#npm-run-build-fails-on-heroku)\n  - [`npm run build` fails to minify](#npm-run-build-fails-to-minify)\n  - [Moment.js locales are missing](#momentjs-locales-are-missing)\n- [Something Missing?](#something-missing)\n\n## Updating to New Releases\n\nCreate React App is divided into two packages:\n\n* `create-react-app` is a global command-line utility that you use to create new projects.\n* `react-scripts` is a development dependency in the generated projects (including this one).\n\nYou almost never need to update `create-react-app` itself: it delegates all the setup to `react-scripts`.\n\nWhen you run `create-react-app`, it always creates the project with the latest version of `react-scripts` so you’ll get all the new features and improvements in newly created apps automatically.\n\nTo update an existing project to a new version of `react-scripts`, [open the changelog](https://github.com/facebookincubator/create-react-app/blob/master/CHANGELOG.md), find the version you’re currently on (check `package.json` in this folder if you’re not sure), and apply the migration instructions for the newer versions.\n\nIn most cases bumping the `react-scripts` version in `package.json` and running `npm install` in this folder should be enough, but it’s good to consult the [changelog](https://github.com/facebookincubator/create-react-app/blob/master/CHANGELOG.md) for potential breaking changes.\n\nWe commit to keeping the breaking changes minimal so you can upgrade `react-scripts` painlessly.\n\n## Sending Feedback\n\nWe are always open to [your feedback](https://github.com/facebookincubator/create-react-app/issues).\n\n## Folder Structure\n\nAfter creation, your project should look like this:\n\n```\nmy-app/\n  README.md\n  node_modules/\n  package.json\n  public/\n    index.html\n    favicon.ico\n  src/\n    App.css\n    App.js\n    App.test.js\n    index.css\n    index.js\n    logo.svg\n```\n\nFor the project to build, **these files must exist with exact filenames**:\n\n* `public/index.html` is the page template;\n* `src/index.js` is the JavaScript entry point.\n\nYou can delete or rename the other files.\n\nYou may create subdirectories inside `src`. For faster rebuilds, only files inside `src` are processed by Webpack.<br>\nYou need to **put any JS and CSS files inside `src`**, otherwise Webpack won’t see them.\n\nOnly files inside `public` can be used from `public/index.html`.<br>\nRead instructions below for using assets from JavaScript and HTML.\n\nYou can, however, create more top-level directories.<br>\nThey will not be included in the production build so you can use them for things like documentation.\n\n## Available Scripts\n\nIn the project directory, you can run:\n\n### `npm start`\n\nRuns the app in the development mode.<br>\nOpen [http://localhost:3000](http://localhost:3000) to view it in the browser.\n\nThe page will reload if you make edits.<br>\nYou will also see any lint errors in the console.\n\n### `npm test`\n\nLaunches the test runner in the interactive watch mode.<br>\nSee the section about [running tests](#running-tests) for more information.\n\n### `npm run build`\n\nBuilds the app for production to the `build` folder.<br>\nIt correctly bundles React in production mode and optimizes the build for the best performance.\n\nThe build is minified and the filenames include the hashes.<br>\nYour app is ready to be deployed!\n\nSee the section about [deployment](#deployment) for more information.\n\n### `npm run eject`\n\n**Note: this is a one-way operation. Once you `eject`, you can’t go back!**\n\nIf you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.\n\nInstead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.\n\nYou don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.\n\n## Supported Language Features and Polyfills\n\nThis project supports a superset of the latest JavaScript standard.<br>\nIn addition to [ES6](https://github.com/lukehoban/es6features) syntax features, it also supports:\n\n* [Exponentiation Operator](https://github.com/rwaldron/exponentiation-operator) (ES2016).\n* [Async/await](https://github.com/tc39/ecmascript-asyncawait) (ES2017).\n* [Object Rest/Spread Properties](https://github.com/sebmarkbage/ecmascript-rest-spread) (stage 3 proposal).\n* [Dynamic import()](https://github.com/tc39/proposal-dynamic-import) (stage 3 proposal)\n* [Class Fields and Static Properties](https://github.com/tc39/proposal-class-public-fields) (part of stage 3 proposal).\n* [JSX](https://facebook.github.io/react/docs/introducing-jsx.html) and [Flow](https://flowtype.org/) syntax.\n\nLearn more about [different proposal stages](https://babeljs.io/docs/plugins/#presets-stage-x-experimental-presets-).\n\nWhile we recommend using experimental proposals with some caution, Facebook heavily uses these features in the product code, so we intend to provide [codemods](https://medium.com/@cpojer/effective-javascript-codemods-5a6686bb46fb) if any of these proposals change in the future.\n\nNote that **the project only includes a few ES6 [polyfills](https://en.wikipedia.org/wiki/Polyfill)**:\n\n* [`Object.assign()`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) via [`object-assign`](https://github.com/sindresorhus/object-assign).\n* [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) via [`promise`](https://github.com/then/promise).\n* [`fetch()`](https://developer.mozilla.org/en/docs/Web/API/Fetch_API) via [`whatwg-fetch`](https://github.com/github/fetch).\n\nIf you use any other ES6+ features that need **runtime support** (such as `Array.from()` or `Symbol`), make sure you are including the appropriate polyfills manually, or that the browsers you are targeting already support them.\n\n## Syntax Highlighting in the Editor\n\nTo configure the syntax highlighting in your favorite text editor, head to the [relevant Babel documentation page](https://babeljs.io/docs/editors) and follow the instructions. Some of the most popular editors are covered.\n\n## Displaying Lint Output in the Editor\n\n>Note: this feature is available with `react-scripts@0.2.0` and higher.<br>\n>It also only works with npm 3 or higher.\n\nSome editors, including Sublime Text, Atom, and Visual Studio Code, provide plugins for ESLint.\n\nThey are not required for linting. You should see the linter output right in your terminal as well as the browser console. However, if you prefer the lint results to appear right in your editor, there are some extra steps you can do.\n\nYou would need to install an ESLint plugin for your editor first. Then, add a file called `.eslintrc` to the project root:\n\n```js\n{\n  \"extends\": \"react-app\"\n}\n```\n\nNow your editor should report the linting warnings.\n\nNote that even if you edit your `.eslintrc` file further, these changes will **only affect the editor integration**. They won’t affect the terminal and in-browser lint output. This is because Create React App intentionally provides a minimal set of rules that find common mistakes.\n\nIf you want to enforce a coding style for your project, consider using [Prettier](https://github.com/jlongster/prettier) instead of ESLint style rules.\n\n## Debugging in the Editor\n\n**This feature is currently only supported by [Visual Studio Code](https://code.visualstudio.com) and [WebStorm](https://www.jetbrains.com/webstorm/).**\n\nVisual Studio Code and WebStorm support debugging out of the box with Create React App. This enables you as a developer to write and debug your React code without leaving the editor, and most importantly it enables you to have a continuous development workflow, where context switching is minimal, as you don’t have to switch between tools.\n\n### Visual Studio Code\n\nYou would need to have the latest version of [VS Code](https://code.visualstudio.com) and VS Code [Chrome Debugger Extension](https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome) installed.\n\nThen add the block below to your `launch.json` file and put it inside the `.vscode` folder in your app’s root directory.\n\n```json\n{\n  \"version\": \"0.2.0\",\n  \"configurations\": [{\n    \"name\": \"Chrome\",\n    \"type\": \"chrome\",\n    \"request\": \"launch\",\n    \"url\": \"http://localhost:3000\",\n    \"webRoot\": \"${workspaceRoot}/src\",\n    \"sourceMapPathOverrides\": {\n      \"webpack:///src/*\": \"${webRoot}/*\"\n    }\n  }]\n}\n```\n>Note: the URL may be different if you've made adjustments via the [HOST or PORT environment variables](#advanced-configuration).\n\nStart your app by running `npm start`, and start debugging in VS Code by pressing `F5` or by clicking the green debug icon. You can now write code, set breakpoints, make changes to the code, and debug your newly modified code—all from your editor.\n\nHaving problems with VS Code Debugging? Please see their [troubleshooting guide](https://github.com/Microsoft/vscode-chrome-debug/blob/master/README.md#troubleshooting).\n\n### WebStorm\n\nYou would need to have [WebStorm](https://www.jetbrains.com/webstorm/) and [JetBrains IDE Support](https://chrome.google.com/webstore/detail/jetbrains-ide-support/hmhgeddbohgjknpmjagkdomcpobmllji) Chrome extension installed.\n\nIn the WebStorm menu `Run` select `Edit Configurations...`. Then click `+` and select `JavaScript Debug`. Paste `http://localhost:3000` into the URL field and save the configuration.\n\n>Note: the URL may be different if you've made adjustments via the [HOST or PORT environment variables](#advanced-configuration).\n\nStart your app by running `npm start`, then press `^D` on macOS or `F9` on Windows and Linux or click the green debug icon to start debugging in WebStorm.\n\nThe same way you can debug your application in IntelliJ IDEA Ultimate, PhpStorm, PyCharm Pro, and RubyMine. \n\n## Formatting Code Automatically\n\nPrettier is an opinionated code formatter with support for JavaScript, CSS and JSON. With Prettier you can format the code you write automatically to ensure a code style within your project. See the [Prettier's GitHub page](https://github.com/prettier/prettier) for more information, and look at this [page to see it in action](https://prettier.github.io/prettier/).\n\nTo format our code whenever we make a commit in git, we need to install the following dependencies:\n\n```sh\nnpm install --save husky lint-staged prettier\n```\n\nAlternatively you may use `yarn`:\n\n```sh\nyarn add husky lint-staged prettier\n```\n\n* `husky` makes it convenient to use githooks as if they are npm scripts.\n* `lint-staged` allows us to run scripts on staged files in git. See this [blog post about lint-staged to learn more about it](https://medium.com/@okonetchnikov/make-linting-great-again-f3890e1ad6b8).\n* `prettier` is the JavaScript formatter we will run before commits.\n\nNow we can make sure every file is formatted correctly by adding a few lines to the `package.json` in the project root.\n\nAdd the following line to `scripts` section:\n\n```diff\n  \"scripts\": {\n+   \"precommit\": \"lint-staged\",\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n```\n\nNext we add a 'lint-staged' field to the `package.json`, for example:\n\n```diff\n  \"dependencies\": {\n    // ...\n  },\n+ \"lint-staged\": {\n+   \"src/**/*.{js,jsx,json,css}\": [\n+     \"prettier --single-quote --write\",\n+     \"git add\"\n+   ]\n+ },\n  \"scripts\": {\n```\n\nNow, whenever you make a commit, Prettier will format the changed files automatically. You can also run `./node_modules/.bin/prettier --single-quote --write \"src/**/*.{js,jsx}\"` to format your entire project for the first time.\n\nNext you might want to integrate Prettier in your favorite editor. Read the section on [Editor Integration](https://github.com/prettier/prettier#editor-integration) on the Prettier GitHub page.\n\n## Changing the Page `<title>`\n\nYou can find the source HTML file in the `public` folder of the generated project. You may edit the `<title>` tag in it to change the title from “React App” to anything else.\n\nNote that normally you wouldn’t edit files in the `public` folder very often. For example, [adding a stylesheet](#adding-a-stylesheet) is done without touching the HTML.\n\nIf you need to dynamically update the page title based on the content, you can use the browser [`document.title`](https://developer.mozilla.org/en-US/docs/Web/API/Document/title) API. For more complex scenarios when you want to change the title from React components, you can use [React Helmet](https://github.com/nfl/react-helmet), a third party library.\n\nIf you use a custom server for your app in production and want to modify the title before it gets sent to the browser, you can follow advice in [this section](#generating-dynamic-meta-tags-on-the-server). Alternatively, you can pre-build each page as a static HTML file which then loads the JavaScript bundle, which is covered [here](#pre-rendering-into-static-html-files).\n\n## Installing a Dependency\n\nThe generated project includes React and ReactDOM as dependencies. It also includes a set of scripts used by Create React App as a development dependency. You may install other dependencies (for example, React Router) with `npm`:\n\n```sh\nnpm install --save react-router\n```\n\nAlternatively you may use `yarn`:\n\n```sh\nyarn add react-router\n```\n\nThis works for any library, not only `react-router`.\n\n## Importing a Component\n\nThis project setup supports ES6 modules thanks to Babel.<br>\nWhile you can still use `require()` and `module.exports`, we encourage you to use [`import` and `export`](http://exploringjs.com/es6/ch_modules.html) instead.\n\nFor example:\n\n### `Button.js`\n\n```js\nimport React, { Component } from 'react';\n\nclass Button extends Component {\n  render() {\n    // ...\n  }\n}\n\nexport default Button; // Don’t forget to use export default!\n```\n\n### `DangerButton.js`\n\n\n```js\nimport React, { Component } from 'react';\nimport Button from './Button'; // Import a component from another file\n\nclass DangerButton extends Component {\n  render() {\n    return <Button color=\"red\" />;\n  }\n}\n\nexport default DangerButton;\n```\n\nBe aware of the [difference between default and named exports](http://stackoverflow.com/questions/36795819/react-native-es-6-when-should-i-use-curly-braces-for-import/36796281#36796281). It is a common source of mistakes.\n\nWe suggest that you stick to using default imports and exports when a module only exports a single thing (for example, a component). That’s what you get when you use `export default Button` and `import Button from './Button'`.\n\nNamed exports are useful for utility modules that export several functions. A module may have at most one default export and as many named exports as you like.\n\nLearn more about ES6 modules:\n\n* [When to use the curly braces?](http://stackoverflow.com/questions/36795819/react-native-es-6-when-should-i-use-curly-braces-for-import/36796281#36796281)\n* [Exploring ES6: Modules](http://exploringjs.com/es6/ch_modules.html)\n* [Understanding ES6: Modules](https://leanpub.com/understandinges6/read#leanpub-auto-encapsulating-code-with-modules)\n\n## Code Splitting\n\nInstead of downloading the entire app before users can use it, code splitting allows you to split your code into small chunks which you can then load on demand.\n\nThis project setup supports code splitting via [dynamic `import()`](http://2ality.com/2017/01/import-operator.html#loading-code-on-demand). Its [proposal](https://github.com/tc39/proposal-dynamic-import) is in stage 3. The `import()` function-like form takes the module name as an argument and returns a [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) which always resolves to the namespace object of the module.\n\nHere is an example:\n\n### `moduleA.js`\n\n```js\nconst moduleA = 'Hello';\n\nexport { moduleA };\n```\n### `App.js`\n\n```js\nimport React, { Component } from 'react';\n\nclass App extends Component {\n  handleClick = () => {\n    import('./moduleA')\n      .then(({ moduleA }) => {\n        // Use moduleA\n      })\n      .catch(err => {\n        // Handle failure\n      });\n  };\n\n  render() {\n    return (\n      <div>\n        <button onClick={this.handleClick}>Load</button>\n      </div>\n    );\n  }\n}\n\nexport default App;\n```\n\nThis will make `moduleA.js` and all its unique dependencies as a separate chunk that only loads after the user clicks the 'Load' button.\n\nYou can also use it with `async` / `await` syntax if you prefer it.\n\n### With React Router\n\nIf you are using React Router check out [this tutorial](http://serverless-stack.com/chapters/code-splitting-in-create-react-app.html) on how to use code splitting with it. You can find the companion GitHub repository [here](https://github.com/AnomalyInnovations/serverless-stack-demo-client/tree/code-splitting-in-create-react-app).\n\n## Adding a Stylesheet\n\nThis project setup uses [Webpack](https://webpack.js.org/) for handling all assets. Webpack offers a custom way of “extending” the concept of `import` beyond JavaScript. To express that a JavaScript file depends on a CSS file, you need to **import the CSS from the JavaScript file**:\n\n### `Button.css`\n\n```css\n.Button {\n  padding: 20px;\n}\n```\n\n### `Button.js`\n\n```js\nimport React, { Component } from 'react';\nimport './Button.css'; // Tell Webpack that Button.js uses these styles\n\nclass Button extends Component {\n  render() {\n    // You can use them as regular CSS styles\n    return <div className=\"Button\" />;\n  }\n}\n```\n\n**This is not required for React** but many people find this feature convenient. You can read about the benefits of this approach [here](https://medium.com/seek-ui-engineering/block-element-modifying-your-javascript-components-d7f99fcab52b). However you should be aware that this makes your code less portable to other build tools and environments than Webpack.\n\nIn development, expressing dependencies this way allows your styles to be reloaded on the fly as you edit them. In production, all CSS files will be concatenated into a single minified `.css` file in the build output.\n\nIf you are concerned about using Webpack-specific semantics, you can put all your CSS right into `src/index.css`. It would still be imported from `src/index.js`, but you could always remove that import if you later migrate to a different build tool.\n\n## Post-Processing CSS\n\nThis project setup minifies your CSS and adds vendor prefixes to it automatically through [Autoprefixer](https://github.com/postcss/autoprefixer) so you don’t need to worry about it.\n\nFor example, this:\n\n```css\n.App {\n  display: flex;\n  flex-direction: row;\n  align-items: center;\n}\n```\n\nbecomes this:\n\n```css\n.App {\n  display: -webkit-box;\n  display: -ms-flexbox;\n  display: flex;\n  -webkit-box-orient: horizontal;\n  -webkit-box-direction: normal;\n      -ms-flex-direction: row;\n          flex-direction: row;\n  -webkit-box-align: center;\n      -ms-flex-align: center;\n          align-items: center;\n}\n```\n\nIf you need to disable autoprefixing for some reason, [follow this section](https://github.com/postcss/autoprefixer#disabling).\n\n## Adding a CSS Preprocessor (Sass, Less etc.)\n\nGenerally, we recommend that you don’t reuse the same CSS classes across different components. For example, instead of using a `.Button` CSS class in `<AcceptButton>` and `<RejectButton>` components, we recommend creating a `<Button>` component with its own `.Button` styles, that both `<AcceptButton>` and `<RejectButton>` can render (but [not inherit](https://facebook.github.io/react/docs/composition-vs-inheritance.html)).\n\nFollowing this rule often makes CSS preprocessors less useful, as features like mixins and nesting are replaced by component composition. You can, however, integrate a CSS preprocessor if you find it valuable. In this walkthrough, we will be using Sass, but you can also use Less, or another alternative.\n\nFirst, let’s install the command-line interface for Sass:\n\n```sh\nnpm install --save node-sass-chokidar\n```\n\nAlternatively you may use `yarn`:\n\n```sh\nyarn add node-sass-chokidar\n```\n\nThen in `package.json`, add the following lines to `scripts`:\n\n```diff\n   \"scripts\": {\n+    \"build-css\": \"node-sass-chokidar src/ -o src/\",\n+    \"watch-css\": \"npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive\",\n     \"start\": \"react-scripts start\",\n     \"build\": \"react-scripts build\",\n     \"test\": \"react-scripts test --env=jsdom\",\n```\n\n>Note: To use a different preprocessor, replace `build-css` and `watch-css` commands according to your preprocessor’s documentation.\n\nNow you can rename `src/App.css` to `src/App.scss` and run `npm run watch-css`. The watcher will find every Sass file in `src` subdirectories, and create a corresponding CSS file next to it, in our case overwriting `src/App.css`. Since `src/App.js` still imports `src/App.css`, the styles become a part of your application. You can now edit `src/App.scss`, and `src/App.css` will be regenerated.\n\nTo share variables between Sass files, you can use Sass imports. For example, `src/App.scss` and other component style files could include `@import \"./shared.scss\";` with variable definitions.\n\nTo enable importing files without using relative paths, you can add the  `--include-path` option to the command in `package.json`.\n\n```\n\"build-css\": \"node-sass-chokidar --include-path ./src --include-path ./node_modules src/ -o src/\",\n\"watch-css\": \"npm run build-css && node-sass-chokidar --include-path ./src --include-path ./node_modules src/ -o src/ --watch --recursive\",\n```\n\nThis will allow you to do imports like\n\n```scss\n@import 'styles/_colors.scss'; // assuming a styles directory under src/\n@import 'nprogress/nprogress'; // importing a css file from the nprogress node module\n```\n\nAt this point you might want to remove all CSS files from the source control, and add `src/**/*.css` to your `.gitignore` file. It is generally a good practice to keep the build products outside of the source control.\n\nAs a final step, you may find it convenient to run `watch-css` automatically with `npm start`, and run `build-css` as a part of `npm run build`. You can use the `&&` operator to execute two scripts sequentially. However, there is no cross-platform way to run two scripts in parallel, so we will install a package for this:\n\n```sh\nnpm install --save npm-run-all\n```\n\nAlternatively you may use `yarn`:\n\n```sh\nyarn add npm-run-all\n```\n\nThen we can change `start` and `build` scripts to include the CSS preprocessor commands:\n\n```diff\n   \"scripts\": {\n     \"build-css\": \"node-sass-chokidar src/ -o src/\",\n     \"watch-css\": \"npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive\",\n-    \"start\": \"react-scripts start\",\n-    \"build\": \"react-scripts build\",\n+    \"start-js\": \"react-scripts start\",\n+    \"start\": \"npm-run-all -p watch-css start-js\",\n+    \"build-js\": \"react-scripts build\",\n+    \"build\": \"npm-run-all build-css build-js\",\n     \"test\": \"react-scripts test --env=jsdom\",\n     \"eject\": \"react-scripts eject\"\n   }\n```\n\nNow running `npm start` and `npm run build` also builds Sass files.\n\n**Why `node-sass-chokidar`?**\n\n`node-sass` has been reported as having the following issues:\n\n- `node-sass --watch` has been reported to have *performance issues* in certain conditions when used in a virtual machine or with docker.\n\n- Infinite styles compiling [#1939](https://github.com/facebookincubator/create-react-app/issues/1939)\n\n- `node-sass` has been reported as having issues with detecting new files in a directory [#1891](https://github.com/sass/node-sass/issues/1891)\n\n `node-sass-chokidar` is used here as it addresses these issues.\n\n## Adding Images, Fonts, and Files\n\nWith Webpack, using static assets like images and fonts works similarly to CSS.\n\nYou can **`import` a file right in a JavaScript module**. This tells Webpack to include that file in the bundle. Unlike CSS imports, importing a file gives you a string value. This value is the final path you can reference in your code, e.g. as the `src` attribute of an image or the `href` of a link to a PDF.\n\nTo reduce the number of requests to the server, importing images that are less than 10,000 bytes returns a [data URI](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) instead of a path. This applies to the following file extensions: bmp, gif, jpg, jpeg, and png. SVG files are excluded due to [#1153](https://github.com/facebookincubator/create-react-app/issues/1153).\n\nHere is an example:\n\n```js\nimport React from 'react';\nimport logo from './logo.png'; // Tell Webpack this JS file uses this image\n\nconsole.log(logo); // /logo.84287d09.png\n\nfunction Header() {\n  // Import result is the URL of your image\n  return <img src={logo} alt=\"Logo\" />;\n}\n\nexport default Header;\n```\n\nThis ensures that when the project is built, Webpack will correctly move the images into the build folder, and provide us with correct paths.\n\nThis works in CSS too:\n\n```css\n.Logo {\n  background-image: url(./logo.png);\n}\n```\n\nWebpack finds all relative module references in CSS (they start with `./`) and replaces them with the final paths from the compiled bundle. If you make a typo or accidentally delete an important file, you will see a compilation error, exactly like when you import a non-existent JavaScript module. The final filenames in the compiled bundle are generated by Webpack from content hashes. If the file content changes in the future, Webpack will give it a different name in production so you don’t need to worry about long-term caching of assets.\n\nPlease be advised that this is also a custom feature of Webpack.\n\n**It is not required for React** but many people enjoy it (and React Native uses a similar mechanism for images).<br>\nAn alternative way of handling static assets is described in the next section.\n\n## Using the `public` Folder\n\n>Note: this feature is available with `react-scripts@0.5.0` and higher.\n\n### Changing the HTML\n\nThe `public` folder contains the HTML file so you can tweak it, for example, to [set the page title](#changing-the-page-title).\nThe `<script>` tag with the compiled code will be added to it automatically during the build process.\n\n### Adding Assets Outside of the Module System\n\nYou can also add other assets to the `public` folder.\n\nNote that we normally encourage you to `import` assets in JavaScript files instead.\nFor example, see the sections on [adding a stylesheet](#adding-a-stylesheet) and [adding images and fonts](#adding-images-fonts-and-files).\nThis mechanism provides a number of benefits:\n\n* Scripts and stylesheets get minified and bundled together to avoid extra network requests.\n* Missing files cause compilation errors instead of 404 errors for your users.\n* Result filenames include content hashes so you don’t need to worry about browsers caching their old versions.\n\nHowever there is an **escape hatch** that you can use to add an asset outside of the module system.\n\nIf you put a file into the `public` folder, it will **not** be processed by Webpack. Instead it will be copied into the build folder untouched.   To reference assets in the `public` folder, you need to use a dedicated variable called `PUBLIC_URL`.\n\nInside `index.html`, you can use it like this:\n\n```html\n<link rel=\"shortcut icon\" href=\"%PUBLIC_URL%/favicon.ico\">\n```\n\nOnly files inside the `public` folder will be accessible by `%PUBLIC_URL%` prefix. If you need to use a file from `src` or `node_modules`, you’ll have to copy it there to explicitly specify your intention to make this file a part of the build.\n\nWhen you run `npm run build`, Create React App will substitute `%PUBLIC_URL%` with a correct absolute path so your project works even if you use client-side routing or host it at a non-root URL.\n\nIn JavaScript code, you can use `process.env.PUBLIC_URL` for similar purposes:\n\n```js\nrender() {\n  // Note: this is an escape hatch and should be used sparingly!\n  // Normally we recommend using `import` for getting asset URLs\n  // as described in “Adding Images and Fonts” above this section.\n  return <img src={process.env.PUBLIC_URL + '/img/logo.png'} />;\n}\n```\n\nKeep in mind the downsides of this approach:\n\n* None of the files in `public` folder get post-processed or minified.\n* Missing files will not be called at compilation time, and will cause 404 errors for your users.\n* Result filenames won’t include content hashes so you’ll need to add query arguments or rename them every time they change.\n\n### When to Use the `public` Folder\n\nNormally we recommend importing [stylesheets](#adding-a-stylesheet), [images, and fonts](#adding-images-fonts-and-files) from JavaScript.\nThe `public` folder is useful as a workaround for a number of less common cases:\n\n* You need a file with a specific name in the build output, such as [`manifest.webmanifest`](https://developer.mozilla.org/en-US/docs/Web/Manifest).\n* You have thousands of images and need to dynamically reference their paths.\n* You want to include a small script like [`pace.js`](http://github.hubspot.com/pace/docs/welcome/) outside of the bundled code.\n* Some library may be incompatible with Webpack and you have no other option but to include it as a `<script>` tag.\n\nNote that if you add a `<script>` that declares global variables, you also need to read the next section on using them.\n\n## Using Global Variables\n\nWhen you include a script in the HTML file that defines global variables and try to use one of these variables in the code, the linter will complain because it cannot see the definition of the variable.\n\nYou can avoid this by reading the global variable explicitly from the `window` object, for example:\n\n```js\nconst $ = window.$;\n```\n\nThis makes it clear you are using a global variable intentionally rather than because of a typo.\n\nAlternatively, you can force the linter to ignore any line by adding `// eslint-disable-line` after it.\n\n## Adding Bootstrap\n\nYou don’t have to use [React Bootstrap](https://react-bootstrap.github.io) together with React but it is a popular library for integrating Bootstrap with React apps. If you need it, you can integrate it with Create React App by following these steps:\n\nInstall React Bootstrap and Bootstrap from npm. React Bootstrap does not include Bootstrap CSS so this needs to be installed as well:\n\n```sh\nnpm install --save react-bootstrap bootstrap@3\n```\n\nAlternatively you may use `yarn`:\n\n```sh\nyarn add react-bootstrap bootstrap@3\n```\n\nImport Bootstrap CSS and optionally Bootstrap theme CSS in the beginning of your ```src/index.js``` file:\n\n```js\nimport 'bootstrap/dist/css/bootstrap.css';\nimport 'bootstrap/dist/css/bootstrap-theme.css';\n// Put any other imports below so that CSS from your\n// components takes precedence over default styles.\n```\n\nImport required React Bootstrap components within ```src/App.js``` file or your custom component files:\n\n```js\nimport { Navbar, Jumbotron, Button } from 'react-bootstrap';\n```\n\nNow you are ready to use the imported React Bootstrap components within your component hierarchy defined in the render method. Here is an example [`App.js`](https://gist.githubusercontent.com/gaearon/85d8c067f6af1e56277c82d19fd4da7b/raw/6158dd991b67284e9fc8d70b9d973efe87659d72/App.js) redone using React Bootstrap.\n\n### Using a Custom Theme\n\nSometimes you might need to tweak the visual styles of Bootstrap (or equivalent package).<br>\nWe suggest the following approach:\n\n* Create a new package that depends on the package you wish to customize, e.g. Bootstrap.\n* Add the necessary build steps to tweak the theme, and publish your package on npm.\n* Install your own theme npm package as a dependency of your app.\n\nHere is an example of adding a [customized Bootstrap](https://medium.com/@tacomanator/customizing-create-react-app-aa9ffb88165) that follows these steps.\n\n## Adding Flow\n\nFlow is a static type checker that helps you write code with fewer bugs. Check out this [introduction to using static types in JavaScript](https://medium.com/@preethikasireddy/why-use-static-types-in-javascript-part-1-8382da1e0adb) if you are new to this concept.\n\nRecent versions of [Flow](http://flowtype.org/) work with Create React App projects out of the box.\n\nTo add Flow to a Create React App project, follow these steps:\n\n1. Run `npm install --save flow-bin` (or `yarn add flow-bin`).\n2. Add `\"flow\": \"flow\"` to the `scripts` section of your `package.json`.\n3. Run `npm run flow init` (or `yarn flow init`) to create a [`.flowconfig` file](https://flowtype.org/docs/advanced-configuration.html) in the root directory.\n4. Add `// @flow` to any files you want to type check (for example, to `src/App.js`).\n\nNow you can run `npm run flow` (or `yarn flow`) to check the files for type errors.\nYou can optionally use an IDE like [Nuclide](https://nuclide.io/docs/languages/flow/) for a better integrated experience.\nIn the future we plan to integrate it into Create React App even more closely.\n\nTo learn more about Flow, check out [its documentation](https://flowtype.org/).\n\n## Adding Custom Environment Variables\n\n>Note: this feature is available with `react-scripts@0.2.3` and higher.\n\nYour project can consume variables declared in your environment as if they were declared locally in your JS files. By\ndefault you will have `NODE_ENV` defined for you, and any other environment variables starting with\n`REACT_APP_`.\n\n**The environment variables are embedded during the build time**. Since Create React App produces a static HTML/CSS/JS bundle, it can’t possibly read them at runtime. To read them at runtime, you would need to load HTML into memory on the server and replace placeholders in runtime, like [described here](#injecting-data-from-the-server-into-the-page). Alternatively you can rebuild the app on the server anytime you change them.\n\n>Note: You must create custom environment variables beginning with `REACT_APP_`. Any other variables except `NODE_ENV` will be ignored to avoid accidentally [exposing a private key on the machine that could have the same name](https://github.com/facebookincubator/create-react-app/issues/865#issuecomment-252199527). Changing any environment variables will require you to restart the development server if it is running.\n\nThese environment variables will be defined for you on `process.env`. For example, having an environment\nvariable named `REACT_APP_SECRET_CODE` will be exposed in your JS as `process.env.REACT_APP_SECRET_CODE`.\n\nThere is also a dedicated built-in environment variable called `NODE_ENV`. You can read it from `process.env.NODE_ENV`. When you run `npm start`, it is always equal to `'development'`, when you run `npm test` it is always equal to `'test'`, and when you run `npm run build` to make a production bundle, it is always equal to `'production'`. **You cannot override `NODE_ENV` manually.** This prevents developers from accidentally deploying a slow development build to production.\n\nThese environment variables can be useful for displaying information conditionally based on where the project is\ndeployed or consuming sensitive data that lives outside of version control.\n\nFirst, you need to have environment variables defined. For example, let’s say you wanted to consume a secret defined\nin the environment inside a `<form>`:\n\n```jsx\nrender() {\n  return (\n    <div>\n      <small>You are running this application in <b>{process.env.NODE_ENV}</b> mode.</small>\n      <form>\n        <input type=\"hidden\" defaultValue={process.env.REACT_APP_SECRET_CODE} />\n      </form>\n    </div>\n  );\n}\n```\n\nDuring the build, `process.env.REACT_APP_SECRET_CODE` will be replaced with the current value of the `REACT_APP_SECRET_CODE` environment variable. Remember that the `NODE_ENV` variable will be set for you automatically.\n\nWhen you load the app in the browser and inspect the `<input>`, you will see its value set to `abcdef`, and the bold text will show the environment provided when using `npm start`:\n\n```html\n<div>\n  <small>You are running this application in <b>development</b> mode.</small>\n  <form>\n    <input type=\"hidden\" value=\"abcdef\" />\n  </form>\n</div>\n```\n\nThe above form is looking for a variable called `REACT_APP_SECRET_CODE` from the environment. In order to consume this\nvalue, we need to have it defined in the environment. This can be done using two ways: either in your shell or in\na `.env` file. Both of these ways are described in the next few sections.\n\nHaving access to the `NODE_ENV` is also useful for performing actions conditionally:\n\n```js\nif (process.env.NODE_ENV !== 'production') {\n  analytics.disable();\n}\n```\n\nWhen you compile the app with `npm run build`, the minification step will strip out this condition, and the resulting bundle will be smaller.\n\n### Referencing Environment Variables in the HTML\n\n>Note: this feature is available with `react-scripts@0.9.0` and higher.\n\nYou can also access the environment variables starting with `REACT_APP_` in the `public/index.html`. For example:\n\n```html\n<title>%REACT_APP_WEBSITE_NAME%</title>\n```\n\nNote that the caveats from the above section apply:\n\n* Apart from a few built-in variables (`NODE_ENV` and `PUBLIC_URL`), variable names must start with `REACT_APP_` to work.\n* The environment variables are injected at build time. If you need to inject them at runtime, [follow this approach instead](#generating-dynamic-meta-tags-on-the-server).\n\n### Adding Temporary Environment Variables In Your Shell\n\nDefining environment variables can vary between OSes. It’s also important to know that this manner is temporary for the\nlife of the shell session.\n\n#### Windows (cmd.exe)\n\n```cmd\nset REACT_APP_SECRET_CODE=abcdef&&npm start\n```\n\n(Note: the lack of whitespace is intentional.)\n\n#### Linux, macOS (Bash)\n\n```bash\nREACT_APP_SECRET_CODE=abcdef npm start\n```\n\n### Adding Development Environment Variables In `.env`\n\n>Note: this feature is available with `react-scripts@0.5.0` and higher.\n\nTo define permanent environment variables, create a file called `.env` in the root of your project:\n\n```\nREACT_APP_SECRET_CODE=abcdef\n```\n\n`.env` files **should be** checked into source control (with the exclusion of `.env*.local`).\n\n#### What other `.env` files can be used?\n\n>Note: this feature is **available with `react-scripts@1.0.0` and higher**.\n\n* `.env`: Default.\n* `.env.local`: Local overrides. **This file is loaded for all environments except test.**\n* `.env.development`, `.env.test`, `.env.production`: Environment-specific settings.\n* `.env.development.local`, `.env.test.local`, `.env.production.local`: Local overrides of environment-specific settings.\n\nFiles on the left have more priority than files on the right:\n\n* `npm start`: `.env.development.local`, `.env.development`, `.env.local`, `.env`\n* `npm run build`: `.env.production.local`, `.env.production`, `.env.local`, `.env`\n* `npm test`: `.env.test.local`, `.env.test`, `.env` (note `.env.local` is missing)\n\nThese variables will act as the defaults if the machine does not explicitly set them.<br>\nPlease refer to the [dotenv documentation](https://github.com/motdotla/dotenv) for more details.\n\n>Note: If you are defining environment variables for development, your CI and/or hosting platform will most likely need\nthese defined as well. Consult their documentation how to do this. For example, see the documentation for [Travis CI](https://docs.travis-ci.com/user/environment-variables/) or [Heroku](https://devcenter.heroku.com/articles/config-vars).\n\n## Can I Use Decorators?\n\nMany popular libraries use [decorators](https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841) in their documentation.<br>\nCreate React App doesn’t support decorator syntax at the moment because:\n\n* It is an experimental proposal and is subject to change.\n* The current specification version is not officially supported by Babel.\n* If the specification changes, we won’t be able to write a codemod because we don’t use them internally at Facebook.\n\nHowever in many cases you can rewrite decorator-based code without decorators.<br>\nPlease refer to these two threads for reference:\n\n* [#214](https://github.com/facebookincubator/create-react-app/issues/214)\n* [#411](https://github.com/facebookincubator/create-react-app/issues/411)\n\nCreate React App will add decorator support when the specification advances to a stable stage.\n\n## Integrating with an API Backend\n\nThese tutorials will help you to integrate your app with an API backend running on another port,\nusing `fetch()` to access it.\n\n### Node\nCheck out [this tutorial](https://www.fullstackreact.com/articles/using-create-react-app-with-a-server/).\nYou can find the companion GitHub repository [here](https://github.com/fullstackreact/food-lookup-demo).\n\n### Ruby on Rails\n\nCheck out [this tutorial](https://www.fullstackreact.com/articles/how-to-get-create-react-app-to-work-with-your-rails-api/).\nYou can find the companion GitHub repository [here](https://github.com/fullstackreact/food-lookup-demo-rails).\n\n## Proxying API Requests in Development\n\n>Note: this feature is available with `react-scripts@0.2.3` and higher.\n\nPeople often serve the front-end React app from the same server and port as their backend implementation.<br>\nFor example, a production setup might look like this after the app is deployed:\n\n```\n/             - static server returns index.html with React app\n/todos        - static server returns index.html with React app\n/api/todos    - server handles any /api/* requests using the backend implementation\n```\n\nSuch setup is **not** required. However, if you **do** have a setup like this, it is convenient to write requests like `fetch('/api/todos')` without worrying about redirecting them to another server or port during development.\n\nTo tell the development server to proxy any unknown requests to your API server in development, add a `proxy` field to your `package.json`, for example:\n\n```js\n  \"proxy\": \"http://localhost:4000\",\n```\n\nThis way, when you `fetch('/api/todos')` in development, the development server will recognize that it’s not a static asset, and will proxy your request to `http://localhost:4000/api/todos` as a fallback. The development server will **only** attempt to send requests without `text/html` in its `Accept` header to the proxy.\n\nConveniently, this avoids [CORS issues](http://stackoverflow.com/questions/21854516/understanding-ajax-cors-and-security-considerations) and error messages like this in development:\n\n```\nFetch API cannot load http://localhost:4000/api/todos. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.\n```\n\nKeep in mind that `proxy` only has effect in development (with `npm start`), and it is up to you to ensure that URLs like `/api/todos` point to the right thing in production. You don’t have to use the `/api` prefix. Any unrecognized request without a `text/html` accept header will be redirected to the specified `proxy`.\n\nThe `proxy` option supports HTTP, HTTPS and WebSocket connections.<br>\nIf the `proxy` option is **not** flexible enough for you, alternatively you can:\n\n* [Configure the proxy yourself](#configuring-the-proxy-manually)\n* Enable CORS on your server ([here’s how to do it for Express](http://enable-cors.org/server_expressjs.html)).\n* Use [environment variables](#adding-custom-environment-variables) to inject the right server hostname and port into your app.\n\n### \"Invalid Host Header\" Errors After Configuring Proxy\n\nWhen you enable the `proxy` option, you opt into a more strict set of hostname checks. This is necessary because leaving the backend open to remote servers makes your computer vulnerable to DNS rebinding attacks. The issue is explained in [this article](https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a) and [this issue](https://github.com/webpack/webpack-dev-server/issues/887).\n\nThis shouldn’t affect you when developing on `localhost`, but if you develop remotely like [described here](https://github.com/facebookincubator/create-react-app/issues/2271), you will see this error in the browser after enabling the `proxy` option:\n\n>Invalid Host header\n\nTo work around it, you can specify your public development server in a file called `.env.development` in the root of your project:\n\n```\nHOST=mypublicdevserver.com\n```\n\nIf you restart the development server now and load the app from the specified server, it should work.\n\nIf you are still having issues or if you’re using a more exotic environment like a cloud editor, you can bypass the server check completely by adding a line to `.env.development.local`. **Note that this is dangerous and exposes your machine to remote code execution from malicious websites:**\n\n```\n# NOTE: THIS IS DANGEROUS!\n# It exposes your machine to attacks from the websites you visit.\nDANGEROUSLY_DISABLE_HOST_CHECK=true\n```\n\nWe don’t recommend this approach.\n\n### Configuring the Proxy Manually\n\n>Note: this feature is available with `react-scripts@1.0.0` and higher.\n\nIf the `proxy` option is **not** flexible enough for you, you can specify an object in the following form (in `package.json`).<br>\nYou may also specify any configuration value [`http-proxy-middleware`](https://github.com/chimurai/http-proxy-middleware#options) or [`http-proxy`](https://github.com/nodejitsu/node-http-proxy#options) supports.\n```js\n{\n  // ...\n  \"proxy\": {\n    \"/api\": {\n      \"target\": \"<url>\",\n      \"ws\": true\n      // ...\n    }\n  }\n  // ...\n}\n```\n\nAll requests matching this path will be proxies, no exceptions. This includes requests for `text/html`, which the standard `proxy` option does not proxy.\n\nIf you need to specify multiple proxies, you may do so by specifying additional entries.\nMatches are regular expressions, so that you can use a regexp to match multiple paths.\n```js\n{\n  // ...\n  \"proxy\": {\n    // Matches any request starting with /api\n    \"/api\": {\n      \"target\": \"<url_1>\",\n      \"ws\": true\n      // ...\n    },\n    // Matches any request starting with /foo\n    \"/foo\": {\n      \"target\": \"<url_2>\",\n      \"ssl\": true,\n      \"pathRewrite\": {\n        \"^/foo\": \"/foo/beta\"\n      }\n      // ...\n    },\n    // Matches /bar/abc.html but not /bar/sub/def.html\n    \"/bar/[^/]*[.]html\": {\n      \"target\": \"<url_3>\",\n      // ...\n    },\n    // Matches /baz/abc.html and /baz/sub/def.html\n    \"/baz/.*/.*[.]html\": {\n      \"target\": \"<url_4>\"\n      // ...\n    }\n  }\n  // ...\n}\n```\n\n### Configuring a WebSocket Proxy\n\nWhen setting up a WebSocket proxy, there are a some extra considerations to be aware of.\n\nIf you’re using a WebSocket engine like [Socket.io](https://socket.io/), you must have a Socket.io server running that you can use as the proxy target. Socket.io will not work with a standard WebSocket server. Specifically, don't expect Socket.io to work with [the websocket.org echo test](http://websocket.org/echo.html).\n\nThere’s some good documentation available for [setting up a Socket.io server](https://socket.io/docs/).\n\nStandard WebSockets **will** work with a standard WebSocket server as well as the websocket.org echo test. You can use libraries like [ws](https://github.com/websockets/ws) for the server, with [native WebSockets in the browser](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket).\n\nEither way, you can proxy WebSocket requests manually in `package.json`:\n\n```js\n{\n  // ...\n  \"proxy\": {\n    \"/socket\": {\n      // Your compatible WebSocket server\n      \"target\": \"ws://<socket_url>\",\n      // Tell http-proxy-middleware that this is a WebSocket proxy.\n      // Also allows you to proxy WebSocket requests without an additional HTTP request\n      // https://github.com/chimurai/http-proxy-middleware#external-websocket-upgrade\n      \"ws\": true\n      // ...\n    }\n  }\n  // ...\n}\n```\n\n## Using HTTPS in Development\n\n>Note: this feature is available with `react-scripts@0.4.0` and higher.\n\nYou may require the dev server to serve pages over HTTPS. One particular case where this could be useful is when using [the \"proxy\" feature](#proxying-api-requests-in-development) to proxy requests to an API server when that API server is itself serving HTTPS.\n\nTo do this, set the `HTTPS` environment variable to `true`, then start the dev server as usual with `npm start`:\n\n#### Windows (cmd.exe)\n\n```cmd\nset HTTPS=true&&npm start\n```\n\n(Note: the lack of whitespace is intentional.)\n\n#### Linux, macOS (Bash)\n\n```bash\nHTTPS=true npm start\n```\n\nNote that the server will use a self-signed certificate, so your web browser will almost definitely display a warning upon accessing the page.\n\n## Generating Dynamic `<meta>` Tags on the Server\n\nSince Create React App doesn’t support server rendering, you might be wondering how to make `<meta>` tags dynamic and reflect the current URL. To solve this, we recommend to add placeholders into the HTML, like this:\n\n```html\n<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta property=\"og:title\" content=\"__OG_TITLE__\">\n    <meta property=\"og:description\" content=\"__OG_DESCRIPTION__\">\n```\n\nThen, on the server, regardless of the backend you use, you can read `index.html` into memory and replace `__OG_TITLE__`, `__OG_DESCRIPTION__`, and any other placeholders with values depending on the current URL. Make sure to sanitize and escape the interpolated values so that they are safe to embed into HTML!\n\nIf you use a Node server, you can even share the route matching logic between the client and the server. However duplicating it also works fine in basic cases.\n\n## Pre-Rendering into Static HTML Files\n\nIf you’re hosting your `build` with a static hosting provider you can use [react-snapshot](https://www.npmjs.com/package/react-snapshot) or [react-snap](https://github.com/stereobooster/react-snap) to generate HTML pages for each route, or relative link, in your application. These pages will then seamlessly become active, or “hydrated”, when the JavaScript bundle has loaded.\n\nThere are also opportunities to use this outside of static hosting, to take the pressure off the server when generating and caching routes.\n\nThe primary benefit of pre-rendering is that you get the core content of each page _with_ the HTML payload—regardless of whether or not your JavaScript bundle successfully downloads. It also increases the likelihood that each route of your application will be picked up by search engines.\n\nYou can read more about [zero-configuration pre-rendering (also called snapshotting) here](https://medium.com/superhighfives/an-almost-static-stack-6df0a2791319).\n\n## Injecting Data from the Server into the Page\n\nSimilarly to the previous section, you can leave some placeholders in the HTML that inject global variables, for example:\n\n```js\n<!doctype html>\n<html lang=\"en\">\n  <head>\n    <script>\n      window.SERVER_DATA = __SERVER_DATA__;\n    </script>\n```\n\nThen, on the server, you can replace `__SERVER_DATA__` with a JSON of real data right before sending the response. The client code can then read `window.SERVER_DATA` to use it. **Make sure to [sanitize the JSON before sending it to the client](https://medium.com/node-security/the-most-common-xss-vulnerability-in-react-js-applications-2bdffbcc1fa0) as it makes your app vulnerable to XSS attacks.**\n\n## Running Tests\n\n>Note: this feature is available with `react-scripts@0.3.0` and higher.<br>\n>[Read the migration guide to learn how to enable it in older projects!](https://github.com/facebookincubator/create-react-app/blob/master/CHANGELOG.md#migrating-from-023-to-030)\n\nCreate React App uses [Jest](https://facebook.github.io/jest/) as its test runner. To prepare for this integration, we did a [major revamp](https://facebook.github.io/jest/blog/2016/09/01/jest-15.html) of Jest so if you heard bad things about it years ago, give it another try.\n\nJest is a Node-based runner. This means that the tests always run in a Node environment and not in a real browser. This lets us enable fast iteration speed and prevent flakiness.\n\nWhile Jest provides browser globals such as `window` thanks to [jsdom](https://github.com/tmpvar/jsdom), they are only approximations of the real browser behavior. Jest is intended to be used for unit tests of your logic and your components rather than the DOM quirks.\n\nWe recommend that you use a separate tool for browser end-to-end tests if you need them. They are beyond the scope of Create React App.\n\n### Filename Conventions\n\nJest will look for test files with any of the following popular naming conventions:\n\n* Files with `.js` suffix in `__tests__` folders.\n* Files with `.test.js` suffix.\n* Files with `.spec.js` suffix.\n\nThe `.test.js` / `.spec.js` files (or the `__tests__` folders) can be located at any depth under the `src` top level folder.\n\nWe recommend to put the test files (or `__tests__` folders) next to the code they are testing so that relative imports appear shorter. For example, if `App.test.js` and `App.js` are in the same folder, the test needs to `import App from './App'` instead of a long relative path. Colocation also helps find tests more quickly in larger projects.\n\n### Command Line Interface\n\nWhen you run `npm test`, Jest will launch in the watch mode. Every time you save a file, it will re-run the tests, exactly like `npm start` recompiles the code.\n\nThe watcher includes an interactive command-line interface with the ability to run all tests, or focus on a search pattern. It is designed this way so that you can keep it open and enjoy fast re-runs. You can learn the commands from the “Watch Usage” note that the watcher prints after every run:\n\n![Jest watch mode](http://facebook.github.io/jest/img/blog/15-watch.gif)\n\n### Version Control Integration\n\nBy default, when you run `npm test`, Jest will only run the tests related to files changed since the last commit. This is an optimization designed to make your tests run fast regardless of how many tests you have. However it assumes that you don’t often commit the code that doesn’t pass the tests.\n\nJest will always explicitly mention that it only ran tests related to the files changed since the last commit. You can also press `a` in the watch mode to force Jest to run all tests.\n\nJest will always run all tests on a [continuous integration](#continuous-integration) server or if the project is not inside a Git or Mercurial repository.\n\n### Writing Tests\n\nTo create tests, add `it()` (or `test()`) blocks with the name of the test and its code. You may optionally wrap them in `describe()` blocks for logical grouping but this is neither required nor recommended.\n\nJest provides a built-in `expect()` global function for making assertions. A basic test could look like this:\n\n```js\nimport sum from './sum';\n\nit('sums numbers', () => {\n  expect(sum(1, 2)).toEqual(3);\n  expect(sum(2, 2)).toEqual(4);\n});\n```\n\nAll `expect()` matchers supported by Jest are [extensively documented here](https://facebook.github.io/jest/docs/en/expect.html#content).<br>\nYou can also use [`jest.fn()` and `expect(fn).toBeCalled()`](https://facebook.github.io/jest/docs/en/expect.html#tohavebeencalled) to create “spies” or mock functions.\n\n### Testing Components\n\nThere is a broad spectrum of component testing techniques. They range from a “smoke test” verifying that a component renders without throwing, to shallow rendering and testing some of the output, to full rendering and testing component lifecycle and state changes.\n\nDifferent projects choose different testing tradeoffs based on how often components change, and how much logic they contain. If you haven’t decided on a testing strategy yet, we recommend that you start with creating basic smoke tests for your components:\n\n```js\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport App from './App';\n\nit('renders without crashing', () => {\n  const div = document.createElement('div');\n  ReactDOM.render(<App />, div);\n});\n```\n\nThis test mounts a component and makes sure that it didn’t throw during rendering. Tests like this provide a lot value with very little effort so they are great as a starting point, and this is the test you will find in `src/App.test.js`.\n\nWhen you encounter bugs caused by changing components, you will gain a deeper insight into which parts of them are worth testing in your application. This might be a good time to introduce more specific tests asserting specific expected output or behavior.\n\nIf you’d like to test components in isolation from the child components they render, we recommend using [`shallow()` rendering API](http://airbnb.io/enzyme/docs/api/shallow.html) from [Enzyme](http://airbnb.io/enzyme/). To install it, run:\n\n```sh\nnpm install --save enzyme enzyme-adapter-react-16 react-test-renderer\n```\n\nAlternatively you may use `yarn`:\n\n```sh\nyarn add enzyme enzyme-adapter-react-16 react-test-renderer\n```\n\nAs of Enzyme 3, you will need to install Enzyme along with an Adapter corresponding to the version of React you are using. (The examples above use the adapter for React 16.)\n\nThe adapter will also need to be configured in your [global setup file](#initializing-test-environment):\n\n#### `src/setupTests.js`\n```js\nimport { configure } from 'enzyme';\nimport Adapter from 'enzyme-adapter-react-16';\n\nconfigure({ adapter: new Adapter() });\n```\n\nNow you can write a smoke test with it:\n\n```js\nimport React from 'react';\nimport { shallow } from 'enzyme';\nimport App from './App';\n\nit('renders without crashing', () => {\n  shallow(<App />);\n});\n```\n\nUnlike the previous smoke test using `ReactDOM.render()`, this test only renders `<App>` and doesn’t go deeper. For example, even if `<App>` itself renders a `<Button>` that throws, this test will pass. Shallow rendering is great for isolated unit tests, but you may still want to create some full rendering tests to ensure the components integrate correctly. Enzyme supports [full rendering with `mount()`](http://airbnb.io/enzyme/docs/api/mount.html), and you can also use it for testing state changes and component lifecycle.\n\nYou can read the [Enzyme documentation](http://airbnb.io/enzyme/) for more testing techniques. Enzyme documentation uses Chai and Sinon for assertions but you don’t have to use them because Jest provides built-in `expect()` and `jest.fn()` for spies.\n\nHere is an example from Enzyme documentation that asserts specific output, rewritten to use Jest matchers:\n\n```js\nimport React from 'react';\nimport { shallow } from 'enzyme';\nimport App from './App';\n\nit('renders welcome message', () => {\n  const wrapper = shallow(<App />);\n  const welcome = <h2>Welcome to React</h2>;\n  // expect(wrapper.contains(welcome)).to.equal(true);\n  expect(wrapper.contains(welcome)).toEqual(true);\n});\n```\n\nAll Jest matchers are [extensively documented here](http://facebook.github.io/jest/docs/en/expect.html).<br>\nNevertheless you can use a third-party assertion library like [Chai](http://chaijs.com/) if you want to, as described below.\n\nAdditionally, you might find [jest-enzyme](https://github.com/blainekasten/enzyme-matchers) helpful to simplify your tests with readable matchers. The above `contains` code can be written in a concise way with jest-enzyme.\n\n```js\nexpect(wrapper).toContainReact(welcome)\n```\n\nTo enable this, install `jest-enzyme`:\n\n```sh\nnpm install --save jest-enzyme\n```\n\nAlternatively you may use `yarn`:\n\n```sh\nyarn add jest-enzyme\n```\n\nImport it in [`src/setupTests.js`](#initializing-test-environment) to make its matchers available in every test:\n\n```js\nimport 'jest-enzyme';\n```\n\n### Using Third Party Assertion Libraries\n\nWe recommend that you use `expect()` for assertions and `jest.fn()` for spies. If you are having issues with them please [file those against Jest](https://github.com/facebook/jest/issues/new), and we’ll fix them. We intend to keep making them better for React, supporting, for example, [pretty-printing React elements as JSX](https://github.com/facebook/jest/pull/1566).\n\nHowever, if you are used to other libraries, such as [Chai](http://chaijs.com/) and [Sinon](http://sinonjs.org/), or if you have existing code using them that you’d like to port over, you can import them normally like this:\n\n```js\nimport sinon from 'sinon';\nimport { expect } from 'chai';\n```\n\nand then use them in your tests like you normally do.\n\n### Initializing Test Environment\n\n>Note: this feature is available with `react-scripts@0.4.0` and higher.\n\nIf your app uses a browser API that you need to mock in your tests or if you only need a global setup before running your tests, add a `src/setupTests.js` to your project. It will be automatically executed before running your tests.\n\nFor example:\n\n#### `src/setupTests.js`\n```js\nconst localStorageMock = {\n  getItem: jest.fn(),\n  setItem: jest.fn(),\n  clear: jest.fn()\n};\nglobal.localStorage = localStorageMock\n```\n\n### Focusing and Excluding Tests\n\nYou can replace `it()` with `xit()` to temporarily exclude a test from being executed.<br>\nSimilarly, `fit()` lets you focus on a specific test without running any other tests.\n\n### Coverage Reporting\n\nJest has an integrated coverage reporter that works well with ES6 and requires no configuration.<br>\nRun `npm test -- --coverage` (note extra `--` in the middle) to include a coverage report like this:\n\n![coverage report](http://i.imgur.com/5bFhnTS.png)\n\nNote that tests run much slower with coverage so it is recommended to run it separately from your normal workflow.\n\n#### Configuration\n\nThe default Jest coverage configuration can be overriden by adding any of the following supported keys to a Jest config in your package.json.\n\nSupported overrides:\n - [`collectCoverageFrom`](https://facebook.github.io/jest/docs/en/configuration.html#collectcoveragefrom-array)\n - [`coverageReporters`](https://facebook.github.io/jest/docs/en/configuration.html#coveragereporters-array-string)\n - [`coverageThreshold`](https://facebook.github.io/jest/docs/en/configuration.html#coveragethreshold-object)\n - [`snapshotSerializers`](https://facebook.github.io/jest/docs/en/configuration.html#snapshotserializers-array-string)\n\nExample package.json:\n\n```json\n{\n  \"name\": \"your-package\",\n  \"jest\": {\n    \"collectCoverageFrom\" : [\n      \"src/**/*.{js,jsx}\",\n      \"!<rootDir>/node_modules/\",\n      \"!<rootDir>/path/to/dir/\"\n    ],\n    \"coverageThreshold\": {\n      \"global\": {\n        \"branches\": 90,\n        \"functions\": 90,\n        \"lines\": 90,\n        \"statements\": 90\n      }\n    },\n    \"coverageReporters\": [\"text\"],\n    \"snapshotSerializers\": [\"my-serializer-module\"]\n  }\n}\n```\n\n### Continuous Integration\n\nBy default `npm test` runs the watcher with interactive CLI. However, you can force it to run tests once and finish the process by setting an environment variable called `CI`.\n\nWhen creating a build of your application with `npm run build` linter warnings are not checked by default. Like `npm test`, you can force the build to perform a linter warning check by setting the environment variable `CI`. If any warnings are encountered then the build fails.\n\nPopular CI servers already set the environment variable `CI` by default but you can do this yourself too:\n\n### On CI servers\n#### Travis CI\n\n1. Following the [Travis Getting started](https://docs.travis-ci.com/user/getting-started/) guide for syncing your GitHub repository with Travis.  You may need to initialize some settings manually in your [profile](https://travis-ci.org/profile) page.\n1. Add a `.travis.yml` file to your git repository.\n```\nlanguage: node_js\nnode_js:\n  - 6\ncache:\n  directories:\n    - node_modules\nscript:\n  - npm run build\n  - npm test\n```\n1. Trigger your first build with a git push.\n1. [Customize your Travis CI Build](https://docs.travis-ci.com/user/customizing-the-build/) if needed.\n\n#### CircleCI\n\nFollow [this article](https://medium.com/@knowbody/circleci-and-zeits-now-sh-c9b7eebcd3c1) to set up CircleCI with a Create React App project.\n\n### On your own environment\n##### Windows (cmd.exe)\n\n```cmd\nset CI=true&&npm test\n```\n\n```cmd\nset CI=true&&npm run build\n```\n\n(Note: the lack of whitespace is intentional.)\n\n##### Linux, macOS (Bash)\n\n```bash\nCI=true npm test\n```\n\n```bash\nCI=true npm run build\n```\n\nThe test command will force Jest to run tests once instead of launching the watcher.\n\n>  If you find yourself doing this often in development, please [file an issue](https://github.com/facebookincubator/create-react-app/issues/new) to tell us about your use case because we want to make watcher the best experience and are open to changing how it works to accommodate more workflows.\n\nThe build command will check for linter warnings and fail if any are found.\n\n### Disabling jsdom\n\nBy default, the `package.json` of the generated project looks like this:\n\n```js\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"test\": \"react-scripts test --env=jsdom\"\n```\n\nIf you know that none of your tests depend on [jsdom](https://github.com/tmpvar/jsdom), you can safely remove `--env=jsdom`, and your tests will run faster:\n\n```diff\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n-   \"test\": \"react-scripts test --env=jsdom\"\n+   \"test\": \"react-scripts test\"\n```\n\nTo help you make up your mind, here is a list of APIs that **need jsdom**:\n\n* Any browser globals like `window` and `document`\n* [`ReactDOM.render()`](https://facebook.github.io/react/docs/top-level-api.html#reactdom.render)\n* [`TestUtils.renderIntoDocument()`](https://facebook.github.io/react/docs/test-utils.html#renderintodocument) ([a shortcut](https://github.com/facebook/react/blob/34761cf9a252964abfaab6faf74d473ad95d1f21/src/test/ReactTestUtils.js#L83-L91) for the above)\n* [`mount()`](http://airbnb.io/enzyme/docs/api/mount.html) in [Enzyme](http://airbnb.io/enzyme/index.html)\n\nIn contrast, **jsdom is not needed** for the following APIs:\n\n* [`TestUtils.createRenderer()`](https://facebook.github.io/react/docs/test-utils.html#shallow-rendering) (shallow rendering)\n* [`shallow()`](http://airbnb.io/enzyme/docs/api/shallow.html) in [Enzyme](http://airbnb.io/enzyme/index.html)\n\nFinally, jsdom is also not needed for [snapshot testing](http://facebook.github.io/jest/blog/2016/07/27/jest-14.html).\n\n### Snapshot Testing\n\nSnapshot testing is a feature of Jest that automatically generates text snapshots of your components and saves them on the disk so if the UI output changes, you get notified without manually writing any assertions on the component output. [Read more about snapshot testing.](http://facebook.github.io/jest/blog/2016/07/27/jest-14.html)\n\n### Editor Integration\n\nIf you use [Visual Studio Code](https://code.visualstudio.com), there is a [Jest extension](https://github.com/orta/vscode-jest) which works with Create React App out of the box. This provides a lot of IDE-like features while using a text editor: showing the status of a test run with potential fail messages inline, starting and stopping the watcher automatically, and offering one-click snapshot updates.\n\n![VS Code Jest Preview](https://cloud.githubusercontent.com/assets/49038/20795349/a032308a-b7c8-11e6-9b34-7eeac781003f.png)\n\n## Developing Components in Isolation\n\nUsually, in an app, you have a lot of UI components, and each of them has many different states.\nFor an example, a plain button component could have following states:\n\n* In a regular state, with a text label.\n* In the disabled mode.\n* In a loading state.\n\nUsually, it’s hard to see these states without running a sample app or some examples.\n\nCreate React App doesn’t include any tools for this by default, but you can add [Storybook for React](https://storybook.js.org) ([source](https://github.com/storybooks/storybook)) or [React Styleguidist](https://react-styleguidist.js.org/) ([source](https://github.com/styleguidist/react-styleguidist)) to your project. **These are third-party tools that let you develop components and see all their states in isolation from your app**.\n\n![Storybook for React Demo](http://i.imgur.com/7CIAWpB.gif)\n\nYou can also deploy your Storybook or style guide as a static app. This way, everyone in your team can view and review different states of UI components without starting a backend server or creating an account in your app.\n\n### Getting Started with Storybook\n\nStorybook is a development environment for React UI components. It allows you to browse a component library, view the different states of each component, and interactively develop and test components.\n\nFirst, install the following npm package globally:\n\n```sh\nnpm install -g @storybook/cli\n```\n\nThen, run the following command inside your app’s directory:\n\n```sh\ngetstorybook\n```\n\nAfter that, follow the instructions on the screen.\n\nLearn more about React Storybook:\n\n* Screencast: [Getting Started with React Storybook](https://egghead.io/lessons/react-getting-started-with-react-storybook)\n* [GitHub Repo](https://github.com/storybooks/storybook)\n* [Documentation](https://storybook.js.org/basics/introduction/)\n* [Snapshot Testing UI](https://github.com/storybooks/storybook/tree/master/addons/storyshots) with Storybook + addon/storyshot\n\n### Getting Started with Styleguidist\n\nStyleguidist combines a style guide, where all your components are presented on a single page with their props documentation and usage examples, with an environment for developing components in isolation, similar to Storybook. In Styleguidist you write examples in Markdown, where each code snippet is rendered as a live editable playground.\n\nFirst, install Styleguidist:\n\n```sh\nnpm install --save react-styleguidist\n```\n\nAlternatively you may use `yarn`:\n\n```sh\nyarn add react-styleguidist\n```\n\nThen, add these scripts to your `package.json`:\n\n```diff\n   \"scripts\": {\n+    \"styleguide\": \"styleguidist server\",\n+    \"styleguide:build\": \"styleguidist build\",\n     \"start\": \"react-scripts start\",\n```\n\nThen, run the following command inside your app’s directory:\n\n```sh\nnpm run styleguide\n```\n\nAfter that, follow the instructions on the screen.\n\nLearn more about React Styleguidist:\n\n* [GitHub Repo](https://github.com/styleguidist/react-styleguidist)\n* [Documentation](https://react-styleguidist.js.org/docs/getting-started.html)\n\n## Making a Progressive Web App\n\nBy default, the production build is a fully functional, offline-first\n[Progressive Web App](https://developers.google.com/web/progressive-web-apps/).\n\nProgressive Web Apps are faster and more reliable than traditional web pages, and provide an engaging mobile experience:\n\n * All static site assets are cached so that your page loads fast on subsequent visits, regardless of network connectivity (such as 2G or 3G). Updates are downloaded in the background.\n * Your app will work regardless of network state, even if offline. This means your users will be able to use your app at 10,000 feet and on the subway.\n * On mobile devices, your app can be added directly to the user's home screen, app icon and all. You can also re-engage users using web **push notifications**. This eliminates the need for the app store.\n\nThe [`sw-precache-webpack-plugin`](https://github.com/goldhand/sw-precache-webpack-plugin)\nis integrated into production configuration,\nand it will take care of generating a service worker file that will automatically\nprecache all of your local assets and keep them up to date as you deploy updates.\nThe service worker will use a [cache-first strategy](https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#cache-falling-back-to-network)\nfor handling all requests for local assets, including the initial HTML, ensuring\nthat your web app is reliably fast, even on a slow or unreliable network.\n\n### Opting Out of Caching\n\nIf you would prefer not to enable service workers prior to your initial\nproduction deployment, then remove the call to `registerServiceWorker()`\nfrom [`src/index.js`](src/index.js).\n\nIf you had previously enabled service workers in your production deployment and\nhave decided that you would like to disable them for all your existing users,\nyou can swap out the call to `registerServiceWorker()` in\n[`src/index.js`](src/index.js) first by modifying the service worker import:\n```javascript\nimport { unregister } from './registerServiceWorker';\n```\nand then call `unregister()` instead.\nAfter the user visits a page that has `unregister()`,\nthe service worker will be uninstalled. Note that depending on how `/service-worker.js` is served,\nit may take up to 24 hours for the cache to be invalidated.\n\n### Offline-First Considerations\n\n1. Service workers [require HTTPS](https://developers.google.com/web/fundamentals/getting-started/primers/service-workers#you_need_https),\nalthough to facilitate local testing, that policy\n[does not apply to `localhost`](http://stackoverflow.com/questions/34160509/options-for-testing-service-workers-via-http/34161385#34161385).\nIf your production web server does not support HTTPS, then the service worker\nregistration will fail, but the rest of your web app will remain functional.\n\n1. Service workers are [not currently supported](https://jakearchibald.github.io/isserviceworkerready/)\nin all web browsers. Service worker registration [won't be attempted](src/registerServiceWorker.js)\non browsers that lack support.\n\n1. The service worker is only enabled in the [production environment](#deployment),\ne.g. the output of `npm run build`. It's recommended that you do not enable an\noffline-first service worker in a development environment, as it can lead to\nfrustration when previously cached assets are used and do not include the latest\nchanges you've made locally.\n\n1. If you *need* to test your offline-first service worker locally, build\nthe application (using `npm run build`) and run a basic http server from your\nbuild directory. After running the build script, `create-react-app` will give\ninstructions for one way to test your production build locally and the [deployment instructions](#deployment) have\ninstructions for using other methods. *Be sure to always use an\nincognito window to avoid complications with your browser cache.*\n\n1. If possible, configure your production environment to serve the generated\n`service-worker.js` [with HTTP caching disabled](http://stackoverflow.com/questions/38843970/service-worker-javascript-update-frequency-every-24-hours).\nIf that's not possible—[GitHub Pages](#github-pages), for instance, does not\nallow you to change the default 10 minute HTTP cache lifetime—then be aware\nthat if you visit your production site, and then revisit again before\n`service-worker.js` has expired from your HTTP cache, you'll continue to get\nthe previously cached assets from the service worker. If you have an immediate\nneed to view your updated production deployment, performing a shift-refresh\nwill temporarily disable the service worker and retrieve all assets from the\nnetwork.\n\n1. Users aren't always familiar with offline-first web apps. It can be useful to\n[let the user know](https://developers.google.com/web/fundamentals/instant-and-offline/offline-ux#inform_the_user_when_the_app_is_ready_for_offline_consumption)\nwhen the service worker has finished populating your caches (showing a \"This web\napp works offline!\" message) and also let them know when the service worker has\nfetched the latest updates that will be available the next time they load the\npage (showing a \"New content is available; please refresh.\" message). Showing\nthis messages is currently left as an exercise to the developer, but as a\nstarting point, you can make use of the logic included in [`src/registerServiceWorker.js`](src/registerServiceWorker.js), which\ndemonstrates which service worker lifecycle events to listen for to detect each\nscenario, and which as a default, only logs appropriate messages to the\nJavaScript console.\n\n1. By default, the generated service worker file will not intercept or cache any\ncross-origin traffic, like HTTP [API requests](#integrating-with-an-api-backend),\nimages, or embeds loaded from a different domain. If you would like to use a\nruntime caching strategy for those requests, you can [`eject`](#npm-run-eject)\nand then configure the\n[`runtimeCaching`](https://github.com/GoogleChrome/sw-precache#runtimecaching-arrayobject)\noption in the `SWPrecacheWebpackPlugin` section of\n[`webpack.config.prod.js`](../config/webpack.config.prod.js).\n\n### Progressive Web App Metadata\n\nThe default configuration includes a web app manifest located at\n[`public/manifest.json`](public/manifest.json), that you can customize with\ndetails specific to your web application.\n\nWhen a user adds a web app to their homescreen using Chrome or Firefox on\nAndroid, the metadata in [`manifest.json`](public/manifest.json) determines what\nicons, names, and branding colors to use when the web app is displayed.\n[The Web App Manifest guide](https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/)\nprovides more context about what each field means, and how your customizations\nwill affect your users' experience.\n\n## Analyzing the Bundle Size\n\n[Source map explorer](https://www.npmjs.com/package/source-map-explorer) analyzes\nJavaScript bundles using the source maps. This helps you understand where code\nbloat is coming from.\n\nTo add Source map explorer to a Create React App project, follow these steps:\n\n```sh\nnpm install --save source-map-explorer\n```\n\nAlternatively you may use `yarn`:\n\n```sh\nyarn add source-map-explorer\n```\n\nThen in `package.json`, add the following line to `scripts`:\n\n```diff\n   \"scripts\": {\n+    \"analyze\": \"source-map-explorer build/static/js/main.*\",\n     \"start\": \"react-scripts start\",\n     \"build\": \"react-scripts build\",\n     \"test\": \"react-scripts test --env=jsdom\",\n```\n\nThen to analyze the bundle run the production build then run the analyze\nscript.\n\n```\nnpm run build\nnpm run analyze\n```\n\n## Deployment\n\n`npm run build` creates a `build` directory with a production build of your app. Set up your favourite HTTP server so that a visitor to your site is served `index.html`, and requests to static paths like `/static/js/main.<hash>.js` are served with the contents of the `/static/js/main.<hash>.js` file.\n\n### Static Server\n\nFor environments using [Node](https://nodejs.org/), the easiest way to handle this would be to install [serve](https://github.com/zeit/serve) and let it handle the rest:\n\n```sh\nnpm install -g serve\nserve -s build\n```\n\nThe last command shown above will serve your static site on the port **5000**. Like many of [serve](https://github.com/zeit/serve)’s internal settings, the port can be adjusted using the `-p` or `--port` flags.\n\nRun this command to get a full list of the options available:\n\n```sh\nserve -h\n```\n\n### Other Solutions\n\nYou don’t necessarily need a static server in order to run a Create React App project in production. It works fine when integrated into an existing dynamic one.\n\nHere’s a programmatic example using [Node](https://nodejs.org/) and [Express](http://expressjs.com/):\n\n```javascript\nconst express = require('express');\nconst path = require('path');\nconst app = express();\n\napp.use(express.static(path.join(__dirname, 'build')));\n\napp.get('/', function (req, res) {\n  res.sendFile(path.join(__dirname, 'build', 'index.html'));\n});\n\napp.listen(9000);\n```\n\nThe choice of your server software isn’t important either. Since Create React App is completely platform-agnostic, there’s no need to explicitly use Node.\n\nThe `build` folder with static assets is the only output produced by Create React App.\n\nHowever this is not quite enough if you use client-side routing. Read the next section if you want to support URLs like `/todos/42` in your single-page app.\n\n### Serving Apps with Client-Side Routing\n\nIf you use routers that use the HTML5 [`pushState` history API](https://developer.mozilla.org/en-US/docs/Web/API/History_API#Adding_and_modifying_history_entries) under the hood (for example, [React Router](https://github.com/ReactTraining/react-router) with `browserHistory`), many static file servers will fail. For example, if you used React Router with a route for `/todos/42`, the development server will respond to `localhost:3000/todos/42` properly, but an Express serving a production build as above will not.\n\nThis is because when there is a fresh page load for a `/todos/42`, the server looks for the file `build/todos/42` and does not find it. The server needs to be configured to respond to a request to `/todos/42` by serving `index.html`. For example, we can amend our Express example above to serve `index.html` for any unknown paths:\n\n```diff\n app.use(express.static(path.join(__dirname, 'build')));\n\n-app.get('/', function (req, res) {\n+app.get('/*', function (req, res) {\n   res.sendFile(path.join(__dirname, 'build', 'index.html'));\n });\n```\n\nIf you’re using [Apache HTTP Server](https://httpd.apache.org/), you need to create a `.htaccess` file in the `public` folder that looks like this:\n\n```\n    Options -MultiViews\n    RewriteEngine On\n    RewriteCond %{REQUEST_FILENAME} !-f\n    RewriteRule ^ index.html [QSA,L]\n```\n\nIt will get copied to the `build` folder when you run `npm run build`. \n\nIf you’re using [Apache Tomcat](http://tomcat.apache.org/), you need to follow [this Stack Overflow answer](https://stackoverflow.com/a/41249464/4878474).\n\nNow requests to `/todos/42` will be handled correctly both in development and in production.\n\nOn a production build, and in a browser that supports [service workers](https://developers.google.com/web/fundamentals/getting-started/primers/service-workers),\nthe service worker will automatically handle all navigation requests, like for\n`/todos/42`, by serving the cached copy of your `index.html`. This\nservice worker navigation routing can be configured or disabled by\n[`eject`ing](#npm-run-eject) and then modifying the\n[`navigateFallback`](https://github.com/GoogleChrome/sw-precache#navigatefallback-string)\nand [`navigateFallbackWhitelist`](https://github.com/GoogleChrome/sw-precache#navigatefallbackwhitelist-arrayregexp)\noptions of the `SWPreachePlugin` [configuration](../config/webpack.config.prod.js).\n\nWhen users install your app to the homescreen of their device the default configuration will make a shortcut to `/index.html`. This may not work for client-side routers which expect the app to be served from `/`. Edit the web app manifest at [`public/manifest.json`](public/manifest.json) and change `start_url` to match the required URL scheme, for example:\n\n```js\n  \"start_url\": \".\",\n```\n\n### Building for Relative Paths\n\nBy default, Create React App produces a build assuming your app is hosted at the server root.<br>\nTo override this, specify the `homepage` in your `package.json`, for example:\n\n```js\n  \"homepage\": \"http://mywebsite.com/relativepath\",\n```\n\nThis will let Create React App correctly infer the root path to use in the generated HTML file.\n\n**Note**: If you are using `react-router@^4`, you can root `<Link>`s using the `basename` prop on any `<Router>`.<br>\nMore information [here](https://reacttraining.com/react-router/web/api/BrowserRouter/basename-string).<br>\n<br>\nFor example:\n```js\n<BrowserRouter basename=\"/calendar\"/>\n<Link to=\"/today\"/> // renders <a href=\"/calendar/today\">\n```\n\n#### Serving the Same Build from Different Paths\n\n>Note: this feature is available with `react-scripts@0.9.0` and higher.\n\nIf you are not using the HTML5 `pushState` history API or not using client-side routing at all, it is unnecessary to specify the URL from which your app will be served. Instead, you can put this in your `package.json`:\n\n```js\n  \"homepage\": \".\",\n```\n\nThis will make sure that all the asset paths are relative to `index.html`. You will then be able to move your app from `http://mywebsite.com` to `http://mywebsite.com/relativepath` or even `http://mywebsite.com/relative/path` without having to rebuild it.\n\n### [Azure](https://azure.microsoft.com/)\n\nSee [this](https://medium.com/@to_pe/deploying-create-react-app-on-microsoft-azure-c0f6686a4321) blog post on how to deploy your React app to Microsoft Azure.\n\n### [Firebase](https://firebase.google.com/)\n\nInstall the Firebase CLI if you haven’t already by running `npm install -g firebase-tools`. Sign up for a [Firebase account](https://console.firebase.google.com/) and create a new project. Run `firebase login` and login with your previous created Firebase account.\n\nThen run the `firebase init` command from your project’s root. You need to choose the **Hosting: Configure and deploy Firebase Hosting sites** and choose the Firebase project you created in the previous step. You will need to agree with `database.rules.json` being created, choose `build` as the public directory, and also agree to **Configure as a single-page app** by replying with `y`.\n\n```sh\n    === Project Setup\n\n    First, let's associate this project directory with a Firebase project.\n    You can create multiple project aliases by running firebase use --add,\n    but for now we'll set up a default project.\n\n    ? What Firebase project do you want to associate as default? Example app (example-app-fd690)\n\n    === Database Setup\n\n    Firebase Realtime Database Rules allow you to define how your data should be\n    structured and when your data can be read from and written to.\n\n    ? What file should be used for Database Rules? database.rules.json\n    ✔  Database Rules for example-app-fd690 have been downloaded to database.rules.json.\n    Future modifications to database.rules.json will update Database Rules when you run\n    firebase deploy.\n\n    === Hosting Setup\n\n    Your public directory is the folder (relative to your project directory) that\n    will contain Hosting assets to uploaded with firebase deploy. If you\n    have a build process for your assets, use your build's output directory.\n\n    ? What do you want to use as your public directory? build\n    ? Configure as a single-page app (rewrite all urls to /index.html)? Yes\n    ✔  Wrote build/index.html\n\n    i  Writing configuration info to firebase.json...\n    i  Writing project information to .firebaserc...\n\n    ✔  Firebase initialization complete!\n```\n\nNow, after you create a production build with `npm run build`, you can deploy it by running `firebase deploy`.\n\n```sh\n    === Deploying to 'example-app-fd690'...\n\n    i  deploying database, hosting\n    ✔  database: rules ready to deploy.\n    i  hosting: preparing build directory for upload...\n    Uploading: [==============================          ] 75%✔  hosting: build folder uploaded successfully\n    ✔  hosting: 8 files uploaded successfully\n    i  starting release process (may take several minutes)...\n\n    ✔  Deploy complete!\n\n    Project Console: https://console.firebase.google.com/project/example-app-fd690/overview\n    Hosting URL: https://example-app-fd690.firebaseapp.com\n```\n\nFor more information see [Add Firebase to your JavaScript Project](https://firebase.google.com/docs/web/setup).\n\n### [GitHub Pages](https://pages.github.com/)\n\n>Note: this feature is available with `react-scripts@0.2.0` and higher.\n\n#### Step 1: Add `homepage` to `package.json`\n\n**The step below is important!**<br>\n**If you skip it, your app will not deploy correctly.**\n\nOpen your `package.json` and add a `homepage` field:\n\n```js\n  \"homepage\": \"https://myusername.github.io/my-app\",\n```\n\nCreate React App uses the `homepage` field to determine the root URL in the built HTML file.\n\n#### Step 2: Install `gh-pages` and add `deploy` to `scripts` in `package.json`\n\nNow, whenever you run `npm run build`, you will see a cheat sheet with instructions on how to deploy to GitHub Pages.\n\nTo publish it at [https://myusername.github.io/my-app](https://myusername.github.io/my-app), run:\n\n```sh\nnpm install --save gh-pages\n```\n\nAlternatively you may use `yarn`:\n\n```sh\nyarn add gh-pages\n```\n\nAdd the following scripts in your `package.json`:\n\n```diff\n  \"scripts\": {\n+   \"predeploy\": \"npm run build\",\n+   \"deploy\": \"gh-pages -d build\",\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n```\n\nThe `predeploy` script will run automatically before `deploy` is run.\n\n#### Step 3: Deploy the site by running `npm run deploy`\n\nThen run:\n\n```sh\nnpm run deploy\n```\n\n#### Step 4: Ensure your project’s settings use `gh-pages`\n\nFinally, make sure **GitHub Pages** option in your GitHub project settings is set to use the `gh-pages` branch:\n\n<img src=\"http://i.imgur.com/HUjEr9l.png\" width=\"500\" alt=\"gh-pages branch setting\">\n\n#### Step 5: Optionally, configure the domain\n\nYou can configure a custom domain with GitHub Pages by adding a `CNAME` file to the `public/` folder.\n\n#### Notes on client-side routing\n\nGitHub Pages doesn’t support routers that use the HTML5 `pushState` history API under the hood (for example, React Router using `browserHistory`). This is because when there is a fresh page load for a url like `http://user.github.io/todomvc/todos/42`, where `/todos/42` is a frontend route, the GitHub Pages server returns 404 because it knows nothing of `/todos/42`. If you want to add a router to a project hosted on GitHub Pages, here are a couple of solutions:\n\n* You could switch from using HTML5 history API to routing with hashes. If you use React Router, you can switch to `hashHistory` for this effect, but the URL will be longer and more verbose (for example, `http://user.github.io/todomvc/#/todos/42?_k=yknaj`). [Read more](https://reacttraining.com/react-router/web/api/Router) about different history implementations in React Router.\n* Alternatively, you can use a trick to teach GitHub Pages to handle 404 by redirecting to your `index.html` page with a dedicated redirect parameter. You would need to add a `404.html` file with the redirection code to the `build` folder before deploying your project, and you’ll need to add code handling the redirect parameter to `index.html`. You can find a detailed explanation of this technique [in this guide](https://github.com/rafrex/spa-github-pages).\n\n### [Heroku](https://www.heroku.com/)\n\nUse the [Heroku Buildpack for Create React App](https://github.com/mars/create-react-app-buildpack).<br>\nYou can find instructions in [Deploying React with Zero Configuration](https://blog.heroku.com/deploying-react-with-zero-configuration).\n\n#### Resolving Heroku Deployment Errors\n\nSometimes `npm run build` works locally but fails during deploy via Heroku. Following are the most common cases.\n\n##### \"Module not found: Error: Cannot resolve 'file' or 'directory'\"\n\nIf you get something like this:\n\n```\nremote: Failed to create a production build. Reason:\nremote: Module not found: Error: Cannot resolve 'file' or 'directory'\nMyDirectory in /tmp/build_1234/src\n```\n\nIt means you need to ensure that the lettercase of the file or directory you `import` matches the one you see on your filesystem or on GitHub.\n\nThis is important because Linux (the operating system used by Heroku) is case sensitive. So `MyDirectory` and `mydirectory` are two distinct directories and thus, even though the project builds locally, the difference in case breaks the `import` statements on Heroku remotes.\n\n##### \"Could not find a required file.\"\n\nIf you exclude or ignore necessary files from the package you will see a error similar this one:\n\n```\nremote: Could not find a required file.\nremote:   Name: `index.html`\nremote:   Searched in: /tmp/build_a2875fc163b209225122d68916f1d4df/public\nremote:\nremote: npm ERR! Linux 3.13.0-105-generic\nremote: npm ERR! argv \"/tmp/build_a2875fc163b209225122d68916f1d4df/.heroku/node/bin/node\" \"/tmp/build_a2875fc163b209225122d68916f1d4df/.heroku/node/bin/npm\" \"run\" \"build\"\n```\n\nIn this case, ensure that the file is there with the proper lettercase and that’s not ignored on your local `.gitignore` or `~/.gitignore_global`.\n\n### [Netlify](https://www.netlify.com/)\n\n**To do a manual deploy to Netlify’s CDN:**\n\n```sh\nnpm install netlify-cli\nnetlify deploy\n```\n\nChoose `build` as the path to deploy.\n\n**To setup continuous delivery:**\n\nWith this setup Netlify will build and deploy when you push to git or open a pull request:\n\n1. [Start a new netlify project](https://app.netlify.com/signup)\n2. Pick your Git hosting service and select your repository\n3. Click `Build your site`\n\n**Support for client-side routing:**\n\nTo support `pushState`, make sure to create a `public/_redirects` file with the following rewrite rules:\n\n```\n/*  /index.html  200\n```\n\nWhen you build the project, Create React App will place the `public` folder contents into the build output.\n\n### [Now](https://zeit.co/now)\n\nNow offers a zero-configuration single-command deployment. You can use `now` to deploy your app for free.\n\n1. Install the `now` command-line tool either via the recommended [desktop tool](https://zeit.co/download) or via node with `npm install -g now`.\n\n2. Build your app by running `npm run build`.\n\n3. Move into the build directory by running `cd build`.\n\n4. Run `now --name your-project-name` from within the build directory. You will see a **now.sh** URL in your output like this:\n\n    ```\n    > Ready! https://your-project-name-tpspyhtdtk.now.sh (copied to clipboard)\n    ```\n\n    Paste that URL into your browser when the build is complete, and you will see your deployed app.\n\nDetails are available in [this article.](https://zeit.co/blog/unlimited-static)\n\n### [S3](https://aws.amazon.com/s3) and [CloudFront](https://aws.amazon.com/cloudfront/)\n\nSee this [blog post](https://medium.com/@omgwtfmarc/deploying-create-react-app-to-s3-or-cloudfront-48dae4ce0af) on how to deploy your React app to Amazon Web Services S3 and CloudFront.\n\n### [Surge](https://surge.sh/)\n\nInstall the Surge CLI if you haven’t already by running `npm install -g surge`. Run the `surge` command and log in you or create a new account.\n\nWhen asked about the project path, make sure to specify the `build` folder, for example:\n\n```sh\n       project path: /path/to/project/build\n```\n\nNote that in order to support routers that use HTML5 `pushState` API, you may want to rename the `index.html` in your build folder to `200.html` before deploying to Surge. This [ensures that every URL falls back to that file](https://surge.sh/help/adding-a-200-page-for-client-side-routing).\n\n## Advanced Configuration\n\nYou can adjust various development and production settings by setting environment variables in your shell or with [.env](#adding-development-environment-variables-in-env).\n\nVariable | Development | Production | Usage\n:--- | :---: | :---: | :---\nBROWSER | :white_check_mark: | :x: | By default, Create React App will open the default system browser, favoring Chrome on macOS. Specify a [browser](https://github.com/sindresorhus/opn#app) to override this behavior, or set it to `none` to disable it completely. If you need to customize the way the browser is launched, you can specify a node script instead. Any arguments passed to `npm start` will also be passed to this script, and the url where your app is served will be the last argument. Your script's file name must have the `.js` extension.\nHOST | :white_check_mark: | :x: | By default, the development web server binds to `localhost`. You may use this variable to specify a different host.\nPORT | :white_check_mark: | :x: | By default, the development web server will attempt to listen on port 3000 or prompt you to attempt the next available port. You may use this variable to specify a different port.\nHTTPS | :white_check_mark: | :x: | When set to `true`, Create React App will run the development server in `https` mode.\nPUBLIC_URL | :x: | :white_check_mark: | Create React App assumes your application is hosted at the serving web server's root or a subpath as specified in [`package.json` (`homepage`)](#building-for-relative-paths). Normally, Create React App ignores the hostname. You may use this variable to force assets to be referenced verbatim to the url you provide (hostname included). This may be particularly useful when using a CDN to host your application.\nCI | :large_orange_diamond: | :white_check_mark: | When set to `true`, Create React App treats warnings as failures in the build. It also makes the test runner non-watching. Most CIs set this flag by default.\nREACT_EDITOR | :white_check_mark: | :x: | When an app crashes in development, you will see an error overlay with clickable stack trace. When you click on it, Create React App will try to determine the editor you are using based on currently running processes, and open the relevant source file. You can [send a pull request to detect your editor of choice](https://github.com/facebookincubator/create-react-app/issues/2636). Setting this environment variable overrides the automatic detection. If you do it, make sure your systems [PATH](https://en.wikipedia.org/wiki/PATH_(variable)) environment variable points to your editor’s bin folder.\nCHOKIDAR_USEPOLLING | :white_check_mark: | :x: | When set to `true`, the watcher runs in polling mode, as necessary inside a VM. Use this option if `npm start` isn't detecting changes.\nGENERATE_SOURCEMAP | :x: | :white_check_mark: | When set to `false`, source maps are not generated for a production build. This solves OOM issues on some smaller machines.\n\n## Troubleshooting\n\n### `npm start` doesn’t detect changes\n\nWhen you save a file while `npm start` is running, the browser should refresh with the updated code.<br>\nIf this doesn’t happen, try one of the following workarounds:\n\n* If your project is in a Dropbox folder, try moving it out.\n* If the watcher doesn’t see a file called `index.js` and you’re referencing it by the folder name, you [need to restart the watcher](https://github.com/facebookincubator/create-react-app/issues/1164) due to a Webpack bug.\n* Some editors like Vim and IntelliJ have a “safe write” feature that currently breaks the watcher. You will need to disable it. Follow the instructions in [“Adjusting Your Text Editor”](https://webpack.js.org/guides/development/#adjusting-your-text-editor).\n* If your project path contains parentheses, try moving the project to a path without them. This is caused by a [Webpack watcher bug](https://github.com/webpack/watchpack/issues/42).\n* On Linux and macOS, you might need to [tweak system settings](https://webpack.github.io/docs/troubleshooting.html#not-enough-watchers) to allow more watchers.\n* If the project runs inside a virtual machine such as (a Vagrant provisioned) VirtualBox, create an `.env` file in your project directory if it doesn’t exist, and add `CHOKIDAR_USEPOLLING=true` to it. This ensures that the next time you run `npm start`, the watcher uses the polling mode, as necessary inside a VM.\n\nIf none of these solutions help please leave a comment [in this thread](https://github.com/facebookincubator/create-react-app/issues/659).\n\n### `npm test` hangs on macOS Sierra\n\nIf you run `npm test` and the console gets stuck after printing `react-scripts test --env=jsdom` to the console there might be a problem with your [Watchman](https://facebook.github.io/watchman/) installation as described in [facebookincubator/create-react-app#713](https://github.com/facebookincubator/create-react-app/issues/713).\n\nWe recommend deleting `node_modules` in your project and running `npm install` (or `yarn` if you use it) first. If it doesn't help, you can try one of the numerous workarounds mentioned in these issues:\n\n* [facebook/jest#1767](https://github.com/facebook/jest/issues/1767)\n* [facebook/watchman#358](https://github.com/facebook/watchman/issues/358)\n* [ember-cli/ember-cli#6259](https://github.com/ember-cli/ember-cli/issues/6259)\n\nIt is reported that installing Watchman 4.7.0 or newer fixes the issue. If you use [Homebrew](http://brew.sh/), you can run these commands to update it:\n\n```\nwatchman shutdown-server\nbrew update\nbrew reinstall watchman\n```\n\nYou can find [other installation methods](https://facebook.github.io/watchman/docs/install.html#build-install) on the Watchman documentation page.\n\nIf this still doesn’t help, try running `launchctl unload -F ~/Library/LaunchAgents/com.github.facebook.watchman.plist`.\n\nThere are also reports that *uninstalling* Watchman fixes the issue. So if nothing else helps, remove it from your system and try again.\n\n### `npm run build` exits too early\n\nIt is reported that `npm run build` can fail on machines with limited memory and no swap space, which is common in cloud environments. Even with small projects this command can increase RAM usage in your system by hundreds of megabytes, so if you have less than 1 GB of available memory your build is likely to fail with the following message:\n\n>  The build failed because the process exited too early. This probably means the system ran out of memory or someone called `kill -9` on the process.\n\nIf you are completely sure that you didn't terminate the process, consider [adding some swap space](https://www.digitalocean.com/community/tutorials/how-to-add-swap-on-ubuntu-14-04) to the machine you’re building on, or build the project locally.\n\n### `npm run build` fails on Heroku\n\nThis may be a problem with case sensitive filenames.\nPlease refer to [this section](#resolving-heroku-deployment-errors).\n\n### Moment.js locales are missing\n\nIf you use a [Moment.js](https://momentjs.com/), you might notice that only the English locale is available by default. This is because the locale files are large, and you probably only need a subset of [all the locales provided by Moment.js](https://momentjs.com/#multiple-locale-support).\n\nTo add a specific Moment.js locale to your bundle, you need to import it explicitly.<br>\nFor example:\n\n```js\nimport moment from 'moment';\nimport 'moment/locale/fr';\n```\n\nIf import multiple locales this way, you can later switch between them by calling `moment.locale()` with the locale name:\n\n```js\nimport moment from 'moment';\nimport 'moment/locale/fr';\nimport 'moment/locale/es';\n\n// ...\n\nmoment.locale('fr');\n```\n\nThis will only work for locales that have been explicitly imported before.\n\n### `npm run build` fails to minify\n\nSome third-party packages don't compile their code to ES5 before publishing to npm. This often causes problems in the ecosystem because neither browsers (except for most modern versions) nor some tools currently support all ES6 features. We recommend to publish code on npm as ES5 at least for a few more years.\n\n<br>\nTo resolve this:\n\n1. Open an issue on the dependency's issue tracker and ask that the package be published pre-compiled.\n  * Note: Create React App can consume both CommonJS and ES modules. For Node.js compatibility, it is recommended that the main entry point is CommonJS. However, they can optionally provide an ES module entry point with the `module` field in `package.json`. Note that **even if a library provides an ES Modules version, it should still precompile other ES6 features to ES5 if it intends to support older browsers**.\n\n2. Fork the package and publish a corrected version yourself. \n\n3. If the dependency is small enough, copy it to your `src/` folder and treat it as application code.\n\nIn the future, we might start automatically compiling incompatible third-party modules, but it is not currently supported. This approach would also slow down the production builds.\n\n## Something Missing?\n\nIf you have ideas for more “How To” recipes that should be on this page, [let us know](https://github.com/facebookincubator/create-react-app/issues) or [contribute some!](https://github.com/facebookincubator/create-react-app/edit/master/packages/react-scripts/template/README.md)\n"
  },
  {
    "path": "examples/draft-0-10-0/playground/package.json",
    "content": "{\n  \"name\": \"playground\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"dependencies\": {\n    \"codemirror\": \"^5.58.3\",\n    \"draft-convert\": \"^2.1.10\",\n    \"draft-js\": \"file:../../..\",\n    \"immutable\": \"^3.7.6\",\n    \"react\": \"^17.0.1\",\n    \"react-app-polyfill\": \"^2.0.0\",\n    \"react-codemirror2\": \"^7.2.1\",\n    \"react-dom\": \"^17.0.1\",\n    \"react-json-tree\": \"^0.13.0\",\n    \"react-panelgroup\": \"^1.0.12\",\n    \"react-scripts\": \"4.0.1\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"test\": \"react-scripts test --env=jsdom\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.2%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  }\n}\n"
  },
  {
    "path": "examples/draft-0-10-0/playground/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n    <meta name=\"theme-color\" content=\"#000000\">\n    <!--\n      manifest.json provides metadata used when your web app is added to the\n      homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/\n    -->\n    <link rel=\"manifest\" href=\"%PUBLIC_URL%/manifest.json\">\n    <link rel=\"shortcut icon\" href=\"%PUBLIC_URL%/favicon.ico\">\n    <!--\n      Notice the use of %PUBLIC_URL% in the tags above.\n      It will be replaced with the URL of the `public` folder during the build.\n      Only files inside the `public` folder can be referenced from the HTML.\n\n      Unlike \"/favicon.ico\" or \"favicon.ico\", \"%PUBLIC_URL%/favicon.ico\" will\n      work correctly both with client-side routing and a non-root public URL.\n      Learn how to configure a non-root public URL by running `npm run build`.\n    -->\n    <title>Draft.js - Playground</title>\n  </head>\n  <body>\n    <noscript>\n      You need to enable JavaScript to run this app.\n    </noscript>\n    <div id=\"root\"></div>\n    <!--\n      This HTML file is a template.\n      If you open it directly in the browser, you will see an empty page.\n\n      You can add webfonts, meta tags, or analytics to this file.\n      The build step will place the bundled scripts into the <body> tag.\n\n      To begin the development, run `npm start` or `yarn start`.\n      To create a production bundle, use `npm run build` or `yarn build`.\n    -->\n  </body>\n</html>\n"
  },
  {
    "path": "examples/draft-0-10-0/playground/public/manifest.json",
    "content": "{\n  \"short_name\": \"Draft.js Playground\",\n  \"name\": \"Draft.js Playground example\",\n  \"icons\": [\n    {\n      \"src\": \"favicon.ico\",\n      \"sizes\": \"64x64 32x32 24x24 16x16\",\n      \"type\": \"image/x-icon\"\n    }\n  ],\n  \"start_url\": \"./index.html\",\n  \"display\": \"standalone\",\n  \"theme_color\": \"#000000\",\n  \"background_color\": \"#ffffff\"\n}\n"
  },
  {
    "path": "examples/draft-0-10-0/playground/src/App.css",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n:root {\n  --nav-main-height: 50px;\n  --main-background: #f7f7f7;\n}\n\n.App {\n  text-align: center;\n}\n\n.playground-main select,\n.playground-main button {\n  color: #fff;\n  font-size: 12px;\n  font-weight: bold;\n  border: none;\n  padding: 0px 10px;\n  height: 24px;\n  border-radius: 4px;\n}\n\n.playground-main select {\n  width: 100px;\n  background: #843131;\n}\n\n.playground-main button {\n  background: #3b3738;\n  margin-left: 10px;\n}\n\n.playground-main button:hover {\n  background: #843131;\n}\n\n.playground-main select:hover,\n.playground-main button:hover {\n  cursor: pointer;\n}\n\n.nav-main {\n  *zoom: 1;\n  background: #3b3738;\n  color: #fafafa;\n  position: fixed;\n  top: 0;\n  height: var(--nav-main-height);\n  box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);\n  width: 100%;\n  z-index: 100;\n  padding: 0 15px;\n}\n\n.nav-main:before,\n.nav-main:after {\n  content: ' ';\n  display: table;\n}\n\n.nav-main:after {\n  clear: both;\n}\n\n.nav-main a {\n  color: #e9e9e9;\n  text-decoration: none;\n}\n\n.nav-main .nav-site {\n  float: right;\n  margin: 0 20px 0 0;\n}\n\n.nav-main .nav-site li {\n  margin: 0;\n}\n\n.nav-main .nav-site a {\n  padding: 0 8px;\n  text-transform: uppercase;\n  letter-spacing: 1px;\n  line-height: 50px;\n  display: inline-block;\n  height: 50px;\n  color: #aaa;\n}\n\n.nav-main .nav-site a:hover {\n  color: #fafafa;\n}\n\n.nav-main .nav-site a.active {\n  color: #fafafa;\n  border-bottom: 3px solid #c15757;\n  background: #333;\n}\n\n.nav-main .nav-home {\n  color: #fafafa;\n  font-size: 24px;\n  line-height: 50px;\n}\n\n.nav-home a {\n  color: #c15757;\n}\n\n.nav-main .nav-experiment-selector option,\n.nav-main .nav-experiment-selector {\n  background: transparent;\n  border: none;\n  color: #fff;\n  cursor: pointer;\n  outline: none;\n  text-align-last: right;\n}\n\n.nav-main .nav-experiment-selector option {\n  color: #000;\n  padding: 10px 0px;\n}\n\n.nav-home img {\n  vertical-align: -17px;\n  margin-right: 4px;\n  width: 50px;\n  height: 50px;\n}\n\n.nav-main ul {\n  display: inline;\n}\n\n.nav-main li {\n  display: inline;\n}\n\n.playground-main {\n  background: var(--main-background);\n  margin-top: var(--nav-main-height);\n  display: flex;\n  height: calc(100vh - var(--nav-main-height));\n  display: flex;\n}\n\n.playground-raw-preview {\n  padding: 10px 20px;\n  display: flex;\n  flex-direction: column;\n  /* justify-content: space-between; */\n}\n\n/**\n * Third-party style overwrites\n */\n.panelWrapper {\n  overflow-y: auto !important;\n}\n\n.playground-raw-preview ul {\n  /** sad :( but seems to not be a way to overwrite that by configuration */\n  background: var(--main-background) !important;\n}\n\n/**\n * basic style for handling nested lists\n */\n.RichEditor-editor li[data-block] li[data-block] {\n  margin-left: 20px;\n}\n"
  },
  {
    "path": "examples/draft-0-10-0/playground/src/App.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * @flow\n * @format\n */\n\nimport './App.css';\nimport './DraftJsPlaygroundContainer.css';\nimport DraftJsRichEditorExample from './DraftJsRichEditorExample';\nimport 'codemirror/lib/codemirror.css';\nimport 'codemirror/mode/javascript/javascript';\nimport {convertToHTML} from 'draft-convert';\nimport {\n  ContentState,\n  EditorState,\n  convertFromHTML as convertFromHTMLClassic,\n  convertFromRaw,\n  convertToRaw,\n} from 'draft-js';\nimport 'draft-js/dist/Draft.css';\nimport convertFromHTMLModern from 'draft-js/lib/convertFromHTMLToContentBlocks';\nimport gkx from 'draft-js/lib/gkx';\nimport Immutable from 'immutable';\nimport React from 'react';\nimport {Controlled as CodeMirror} from 'react-codemirror2';\nimport JSONTree from 'react-json-tree';\nimport PanelGroup from 'react-panelgroup';\n\nconst fromHTML = gkx('draft_refactored_html_importer')\n  ? convertFromHTMLModern\n  : convertFromHTMLClassic;\n\nconst theme = {\n  scheme: 'monokai',\n  author: 'wimer hazenberg (http://www.monokai.nl)',\n  base00: '#000000',\n  base01: '#383830',\n  base02: '#49483e',\n  base03: '#75715e',\n  base04: '#a59f85',\n  base05: '#f8f8f2',\n  base06: '#f5f4f1',\n  base07: '#f9f8f5',\n  base08: '#f92672',\n  base09: '#fd971f',\n  base0A: '#f4bf75',\n  base0B: '#a6e22e',\n  base0C: '#a1efe4',\n  base0D: '#66d9ef',\n  base0E: '#ae81ff',\n  base0F: '#cc6633',\n};\n\nconst baseRawContent = {\n  blocks: [\n    {\n      key: 'A',\n      text: 'Hello world',\n      type: 'header-one',\n    },\n  ],\n  entityMap: {},\n};\n\nconst baseHtmlContent = `<ol>\n  <li>one</li>\n  <li>\n    <ul>\n      <li>\n        <h1>2a</h1>\n      </li>\n      <li>2b</li>\n    </ul>\n   </li>\n   <li>three</li>\n</ol>\n`;\n\nconst BASE_CONTENT = {\n  rawContent: JSON.stringify(baseRawContent, null, 2),\n  html: baseHtmlContent,\n};\n\nclass DraftJsPlaygroundContainer extends React.Component {\n  constructor(props) {\n    super(props);\n    this.state = {\n      mode: 'rawContent',\n      editorState: EditorState.createEmpty(),\n      codeMirrorValue: BASE_CONTENT['rawContent'],\n      showAllState: false,\n    };\n  }\n\n  componentDidMount() {\n    this.setContent();\n  }\n\n  onChange = (editorState) => {\n    this.setState({editorState});\n  };\n\n  _setContentBlock(content) {\n    this.onChange(EditorState.createWithContent(content));\n  }\n\n  importEditorState = () => {\n    const {editorState, mode} = this.state;\n    if (mode === 'html') {\n      this.setState({\n        codeMirrorValue: convertToHTML(editorState.getCurrentContent()),\n      });\n    } else {\n      this.setState({\n        codeMirrorValue: JSON.stringify(\n          convertToRaw(editorState.getCurrentContent()),\n          null,\n          2,\n        ),\n      });\n    }\n  };\n\n  _setHTMLContent(html) {\n    const parsedHtml = fromHTML(html);\n    if (!parsedHtml) {\n      return;\n    }\n\n    const {contentBlocks, entityMap} = parsedHtml;\n    if (!contentBlocks) {\n      return;\n    }\n\n    this._setContentBlock(\n      ContentState.createFromBlockArray(contentBlocks, entityMap),\n    );\n  }\n\n  _setRawContent(rawContent) {\n    try {\n      const parsedJson = JSON.parse(rawContent);\n      this._setContentBlock(convertFromRaw(parsedJson));\n    } catch (err) {\n      alert('The json is invalid');\n    }\n  }\n\n  setContent = () => {\n    const {mode, codeMirrorValue} = this.state;\n    if (mode === 'html') {\n      this._setHTMLContent(codeMirrorValue);\n    } else {\n      this._setRawContent(codeMirrorValue);\n    }\n  };\n\n  onSelectChange = ({target: {value: mode}}) => {\n    this.setState({\n      mode,\n      codeMirrorValue: BASE_CONTENT[mode],\n    });\n  };\n\n  updateCodeMirror = (codeMirrorValue) => {\n    this.setState({codeMirrorValue});\n  };\n\n  shouldExpandNode = (keyName, data, level) => {\n    return ['blockMap', 'root'].some(\n      (defaultVisibleNode) => keyName[0] === defaultVisibleNode,\n    );\n  };\n\n  onExperimentChange = ({target: {value: experimentFlags}}) => {\n    if (experimentFlags) {\n      window.location.search = `gk_enable=${experimentFlags}`;\n    }\n  };\n\n  render() {\n    const {editorState, mode, codeMirrorValue, showAllState} = this.state;\n\n    return (\n      <div className=\"container\">\n        <div className=\"nav-main\">\n          <div className=\"wrap\">\n            <a\n              className=\"nav-home\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n              href=\"https://draftjs.org/\"\n            >\n              Draft.js\n            </a>\n            <ul className=\"nav-site\">\n              <li>\n                <select\n                  className=\"nav-experiment-selector\"\n                  name=\"experiment\"\n                  onChange={this.onExperimentChange}\n                >\n                  <option value=\"\">Try an experiment..</option>\n                  <option value=\"draft_refactored_html_importer\">\n                    Modern HTML importer\n                  </option>\n                  <option value=\"draft_tree_data_support,draft_refactored_html_importer\">\n                    Tree data structure\n                  </option>\n                </select>\n              </li>\n              <li>\n                <a\n                  target=\"_blank\"\n                  rel=\"noopener noreferrer\"\n                  href=\"https://draftjs.org/docs/getting-started\"\n                >\n                  Docs\n                </a>\n              </li>\n              <li>\n                <a\n                  target=\"_blank\"\n                  rel=\"noopener noreferrer\"\n                  href=\"https://github.com/facebook/draft-js\"\n                >\n                  GitHub\n                </a>\n              </li>\n            </ul>\n          </div>\n        </div>\n        <div className=\"playground-main\">\n          <PanelGroup borderColor=\"grey\">\n            <PanelGroup direction=\"column\" borderColor=\"grey\">\n              <div className=\"DraftJsPlaygroundContainer-editor\">\n                <DraftJsRichEditorExample\n                  className=\"DraftEditor-root\"\n                  editorState={editorState}\n                  onChange={this.onChange}\n                  placeholder=\"Editor content is empty...\"\n                />\n              </div>\n              <div className=\"DraftJsPlaygroundContainer-raw\">\n                <div className=\"DraftJsPlaygroundContainer-controls\">\n                  <section className=\"contentControls\">\n                    <select\n                      title=\"Draft.js content type switch\"\n                      onChange={this.onSelectChange}\n                      value={mode}\n                    >\n                      <option value=\"rawContent\">Raw</option>\n                      <option value=\"html\">HTML</option>\n                    </select>\n                  </section>\n                  <section className=\"contentControls\">\n                    <button\n                      title=\"Import content type from the editor\"\n                      onClick={this.importEditorState}\n                    >\n                      Import\n                    </button>\n                    <button\n                      title=\"Update the editor with content type\"\n                      onClick={this.setContent}\n                    >\n                      Update\n                    </button>\n                  </section>\n                </div>\n                <CodeMirror\n                  onBeforeChange={(editor, data, codeMirrorValue) =>\n                    this.updateCodeMirror(codeMirrorValue)\n                  }\n                  ref={(input) => {\n                    this.markupinput = input;\n                  }}\n                  options={{\n                    mode: 'application/ld+json',\n                    matchBrackets: true,\n                    lineNumbers: true,\n                    lineWrapping: true,\n                    autoCloseBrackets: true,\n                  }}\n                  value={codeMirrorValue}\n                />\n              </div>\n            </PanelGroup>\n            <div className=\"playground-raw-preview\">\n              <select\n                style={{flexShrink: 0, width: '11em'}}\n                onChange={(e) =>\n                  this.setState({showAllState: e.target.value === 'all'})\n                }\n              >\n                <option value=\"content\">Current Content</option>\n                <option value=\"all\">All State</option>\n              </select>\n              {this.state.showAllState && (\n                <small style={{marginTop: 8, color: 'grey'}}>\n                  Not all this state is accessible via the Draft.js API. Some is\n                  internal and shouldn't be directly changed by editors. Use\n                  this view when developing Draft.js itself.\n                </small>\n              )}\n              <JSONTree\n                shouldExpandNode={this.shouldExpandNode}\n                theme={theme}\n                data={\n                  showAllState\n                    ? editorState._immutable\n                    : editorState.getCurrentContent()\n                }\n                getItemString={(type, data, itemType, itemString) => {\n                  return (\n                    <span\n                      title={data.constructor.name}\n                      style={{\n                        color: Immutable.Iterable.isIterable(data)\n                          ? '#E85351'\n                          : 'gray',\n                      }}\n                    >\n                      {itemString}\n                    </span>\n                  );\n                }}\n              />\n            </div>\n          </PanelGroup>\n        </div>\n      </div>\n    );\n  }\n}\n\nexport default DraftJsPlaygroundContainer;\n"
  },
  {
    "path": "examples/draft-0-10-0/playground/src/App.test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport App from './App';\n\nit('renders without crashing', () => {\n  const div = document.createElement('div');\n  ReactDOM.render(<App />, div);\n});\n"
  },
  {
    "path": "examples/draft-0-10-0/playground/src/DraftJsPlaygroundContainer.css",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n.DraftJsPlaygroundContainer-container {\n  background: white;\n  display: flex;\n  flex-flow: row wrap;\n  font-weight: bold;\n  height: 100%;\n}\n\n.DraftJsPlaygroundContainer-column {\n  border-bottom: 4px solid blue;\n  border-right: 4px solid blue;\n  flex: 1 1 0;\n  padding: 5px 10px;\n}\n\n.DraftJsPlaygroundContainer-column:first-child {\n  border-left: 4px solid blue;\n}\n\n.DraftJsPlaygroundContainer-controls {\n  display: flex;\n  justify-content: space-between;\n  background: #eee;\n  padding: 0.5em;\n}\n\n.DraftJsPlaygroundContainer-raw {\n  width: 100%;\n}\n\n.DraftJsPlaygroundContainer-container [data-block] {\n  border: 1px dashed #000;\n  margin-left: 30px;\n  padding: 10px;\n}\n\n.DraftJsPlaygroundContainer-container [data-contents] > [data-block] {\n  border-left: none;\n  border-right: none;\n  margin-left: 0;\n}\n\n.DraftJsPlaygroundContainer-container\n  [data-contents]\n  > [data-block]:first-child {\n  border-top: none;\n}\n\n.DraftJsPlaygroundContainer-container\n  [data-contents]\n  > [data-block]:last-child {\n  border-bottom: none;\n}\n\n.DraftJsPlaygroundContainer-button {\n  margin-top: 10px;\n  text-align: center;\n}\n\n.DraftJsPlaygroundContainer-inputArea {\n  background: white;\n  display: block;\n  width: 100%;\n}\n\n.DraftJsPlaygroundContainer-editor {\n  background: white;\n  width: 100%;\n  padding: 1em;\n  height: 100%;\n}\n\n.DraftJsPlaygroundContainer-stateViewer {\n  padding: 0px 20px;\n  text-align: left;\n}\n"
  },
  {
    "path": "examples/draft-0-10-0/playground/src/DraftJsRichEditorExample.css",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n.DraftJsPlaygroundContainer-editor {\n  padding: 0;\n  background: #fff;\n  height: auto;\n}\n\n.RichEditor-root {\n  background: #fff;\n  font-family: 'Georgia', serif;\n  font-size: 14px;\n  padding: 15px;\n}\n\n.RichEditor-editor {\n  cursor: text;\n  font-size: 16px;\n}\n\n.RichEditor-editor .public-DraftEditorPlaceholder-root,\n.RichEditor-editor .public-DraftEditor-content {\n  margin: 0 -15px -15px;\n  padding: 15px;\n}\n\n.RichEditor-editor .public-DraftEditor-content {\n  min-height: 100px;\n}\n\n.RichEditor-hidePlaceholder .public-DraftEditorPlaceholder-root {\n  display: none;\n}\n\n.RichEditor-editor .RichEditor-blockquote {\n  border-left: 5px solid #eee;\n  color: #666;\n  font-family: 'Hoefler Text', 'Georgia', serif;\n  font-style: italic;\n  margin: 16px 0;\n  padding: 10px 20px;\n}\n\n.RichEditor-editor .public-DraftStyleDefault-pre {\n  background-color: rgba(0, 0, 0, 0.05);\n  font-family: 'Inconsolata', 'Menlo', 'Consolas', monospace;\n  font-size: 16px;\n  padding: 20px;\n}\n\n.RichEditor-controls-container {\n  border-bottom: 1px solid #ccc;\n  background: #fff;\n  z-index: 10;\n}\n\n.RichEditor-controls {\n  font-family: 'Helvetica', sans-serif;\n  font-size: 14px;\n  margin-bottom: 5px;\n  user-select: none;\n}\n\n.RichEditor-styleButton {\n  color: #999;\n  cursor: pointer;\n  margin-right: 16px;\n  padding: 2px 0;\n  display: inline-block;\n}\n\n.RichEditor-activeButton {\n  color: #5890ff;\n}\n"
  },
  {
    "path": "examples/draft-0-10-0/playground/src/DraftJsRichEditorExample.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * @flow\n * @format\n */\n\nimport './DraftJsRichEditorExample.css';\nimport {Editor, RichUtils, getDefaultKeyBinding} from 'draft-js';\nimport gkx from 'draft-js/lib/gkx';\nimport NestedRichTextEditorUtil from 'draft-js/lib/NestedRichTextEditorUtil';\nimport React from 'react';\n\nconst RichTextUtils = gkx('draft_tree_data_support')\n  ? NestedRichTextEditorUtil\n  : RichUtils;\n\nclass DraftJsRichEditorExample extends React.Component {\n  focus = () => this.refs.editor.focus();\n\n  handleKeyCommand = (command, editorState) => {\n    const newState = RichTextUtils.handleKeyCommand(editorState, command);\n    if (newState) {\n      this.props.onChange(newState);\n      return true;\n    }\n    return false;\n  };\n\n  mapKeyToEditorCommand = (e) => {\n    if (e.keyCode === 9 /* TAB */) {\n      const newEditorState = RichTextUtils.onTab(\n        e,\n        this.props.editorState,\n        4 /* maxDepth */,\n      );\n      if (newEditorState !== this.props.editorState) {\n        this.props.onChange(newEditorState);\n      }\n      return false;\n    }\n    return getDefaultKeyBinding(e);\n  };\n\n  toggleBlockType = (blockType) => {\n    this.props.onChange(\n      RichTextUtils.toggleBlockType(this.props.editorState, blockType),\n    );\n  };\n\n  toggleInlineStyle = (inlineStyle) => {\n    this.props.onChange(\n      RichTextUtils.toggleInlineStyle(this.props.editorState, inlineStyle),\n    );\n  };\n\n  render() {\n    const {editorState} = this.props;\n\n    // If the user changes block type before entering any text, we can\n    // either style the placeholder or hide it. Let's just hide it now.\n    let className = 'RichEditor-editor';\n    const contentState = editorState.getCurrentContent();\n    if (!contentState.hasText()) {\n      if (contentState.getBlockMap().first().getType() !== 'unstyled') {\n        className += ' RichEditor-hidePlaceholder';\n      }\n    }\n\n    return (\n      <div className=\"RichEditor-root\">\n        <div className=\"RichEditor-controls-container\">\n          <BlockStyleControls\n            editorState={editorState}\n            onToggle={this.toggleBlockType}\n          />\n          <InlineStyleControls\n            editorState={editorState}\n            onToggle={this.toggleInlineStyle}\n          />\n        </div>\n        <div className={className} onClick={this.focus}>\n          <Editor\n            blockStyleFn={getBlockStyle}\n            customStyleMap={styleMap}\n            editorState={editorState}\n            handleKeyCommand={this.handleKeyCommand}\n            keyBindingFn={this.mapKeyToEditorCommand}\n            onChange={this.props.onChange}\n            placeholder={this.props.placeholder}\n            ref=\"editor\"\n            spellCheck={true}\n          />\n        </div>\n      </div>\n    );\n  }\n}\n\n// Custom overrides for \"code\" style.\nconst styleMap = {\n  CODE: {\n    backgroundColor: 'rgba(0, 0, 0, 0.05)',\n    fontFamily: '\"Inconsolata\", \"Menlo\", \"Consolas\", monospace',\n    fontSize: 16,\n    padding: 2,\n  },\n};\n\nfunction getBlockStyle(block) {\n  switch (block.getType()) {\n    case 'blockquote':\n      return 'RichEditor-blockquote';\n    default:\n      return null;\n  }\n}\n\nfunction StyleButton({active, style, label, onToggle}) {\n  let className = 'RichEditor-styleButton';\n  if (active) {\n    className += ' RichEditor-activeButton';\n  }\n\n  return (\n    <span\n      className={className}\n      onMouseDown={(e) => {\n        e.preventDefault();\n        onToggle(style);\n      }}\n    >\n      {label}\n    </span>\n  );\n}\n\nconst BLOCK_TYPES = [\n  {label: 'H1', style: 'header-one'},\n  {label: 'H2', style: 'header-two'},\n  {label: 'H3', style: 'header-three'},\n  {label: 'H4', style: 'header-four'},\n  {label: 'H5', style: 'header-five'},\n  {label: 'H6', style: 'header-six'},\n  {label: 'Blockquote', style: 'blockquote'},\n  {label: 'UL', style: 'unordered-list-item'},\n  {label: 'OL', style: 'ordered-list-item'},\n  {label: 'Code Block', style: 'code-block'},\n];\n\nfunction BlockStyleControls(props) {\n  const {editorState} = props;\n  const selection = editorState.getSelection();\n  const blockType = editorState\n    .getCurrentContent()\n    .getBlockForKey(selection.getStartKey())\n    .getType();\n\n  return (\n    <div className=\"RichEditor-controls\">\n      {BLOCK_TYPES.map((type) => (\n        <StyleButton\n          key={type.label}\n          active={type.style === blockType}\n          label={type.label}\n          onToggle={props.onToggle}\n          style={type.style}\n        />\n      ))}\n    </div>\n  );\n}\n\nconst INLINE_STYLES = [\n  {label: 'Bold', style: 'BOLD'},\n  {label: 'Italic', style: 'ITALIC'},\n  {label: 'Underline', style: 'UNDERLINE'},\n  {label: 'Monospace', style: 'CODE'},\n];\n\nfunction InlineStyleControls(props) {\n  const currentStyle = props.editorState.getCurrentInlineStyle();\n\n  return (\n    <div className=\"RichEditor-controls\">\n      {INLINE_STYLES.map((type) => (\n        <StyleButton\n          key={type.label}\n          active={currentStyle.has(type.style)}\n          label={type.label}\n          onToggle={props.onToggle}\n          style={type.style}\n        />\n      ))}\n    </div>\n  );\n}\n\nexport default DraftJsRichEditorExample;\n"
  },
  {
    "path": "examples/draft-0-10-0/playground/src/GkManager.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\nimport querystring from 'querystring';\n\nconst QUERY_STRINGS = querystring.parse(window.location.search.substring(1));\n\n// overwrite the feature flag stub object\nconst GKManager = (window.__DRAFT_GKX = {});\n\n// enable or disable feature flags\nconst flagControls = {\n  gk_disable: flags =>\n    flags.forEach(flag => (window.__DRAFT_GKX[flag] = false)),\n  gk_enable: flags => flags.forEach(flag => (window.__DRAFT_GKX[flag] = true)),\n};\n\nObject.keys(flagControls)\n  .filter(flag => QUERY_STRINGS[flag])\n  .forEach(flag => flagControls[flag](QUERY_STRINGS[flag].split(',')));\n\nexport default GKManager;\n"
  },
  {
    "path": "examples/draft-0-10-0/playground/src/index.css",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\nbody {\n  margin: 0;\n  padding: 0;\n  font-family: sans-serif;\n}\n\n#root {\n  position: fixed;\n  height: 100vh;\n  width: 100%;\n}\n"
  },
  {
    "path": "examples/draft-0-10-0/playground/src/index.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\nimport 'react-app-polyfill/ie9'; // For IE 9-11 support\n\nimport GkManager from './GkManager';\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport './index.css';\nimport App from './App';\nimport registerServiceWorker from './registerServiceWorker';\n\nconsole.log(\"Applying feature flag overwrites: \", GkManager);\n\nReactDOM.render(<App />, document.getElementById('root'));\nregisterServiceWorker();\n"
  },
  {
    "path": "examples/draft-0-10-0/playground/src/registerServiceWorker.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n// In production, we register a service worker to serve assets from local cache.\n\n// This lets the app load faster on subsequent visits in production, and gives\n// it offline capabilities. However, it also means that developers (and users)\n// will only see deployed updates on the \"N+1\" visit to a page, since previously\n// cached resources are updated in the background.\n\n// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.\n// This link also includes instructions on opting out of this behavior.\n\nconst isLocalhost = Boolean(\n  window.location.hostname === 'localhost' ||\n    // [::1] is the IPv6 localhost address.\n    window.location.hostname === '[::1]' ||\n    // 127.0.0.1/8 is considered localhost for IPv4.\n    window.location.hostname.match(\n      /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\n    )\n);\n\nexport default function register() {\n  if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\n    // The URL constructor is available in all browsers that support SW.\n    const publicUrl = new URL(process.env.PUBLIC_URL, window.location);\n    if (publicUrl.origin !== window.location.origin) {\n      // Our service worker won't work if PUBLIC_URL is on a different origin\n      // from what our page is served on. This might happen if a CDN is used to\n      // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374\n      return;\n    }\n\n    window.addEventListener('load', () => {\n      const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\n\n      if (isLocalhost) {\n        // This is running on localhost. Lets check if a service worker still exists or not.\n        checkValidServiceWorker(swUrl);\n      } else {\n        // Is not local host. Just register service worker\n        registerValidSW(swUrl);\n      }\n    });\n  }\n}\n\nfunction registerValidSW(swUrl) {\n  navigator.serviceWorker\n    .register(swUrl)\n    .then(registration => {\n      registration.onupdatefound = () => {\n        const installingWorker = registration.installing;\n        installingWorker.onstatechange = () => {\n          if (installingWorker.state === 'installed') {\n            if (navigator.serviceWorker.controller) {\n              // At this point, the old content will have been purged and\n              // the fresh content will have been added to the cache.\n              // It's the perfect time to display a \"New content is\n              // available; please refresh.\" message in your web app.\n              console.log('New content is available; please refresh.');\n            } else {\n              // At this point, everything has been precached.\n              // It's the perfect time to display a\n              // \"Content is cached for offline use.\" message.\n              console.log('Content is cached for offline use.');\n            }\n          }\n        };\n      };\n    })\n    .catch(error => {\n      console.error('Error during service worker registration:', error);\n    });\n}\n\nfunction checkValidServiceWorker(swUrl) {\n  // Check if the service worker can be found. If it can't reload the page.\n  fetch(swUrl)\n    .then(response => {\n      // Ensure service worker exists, and that we really are getting a JS file.\n      if (\n        response.status === 404 ||\n        response.headers.get('content-type').indexOf('javascript') === -1\n      ) {\n        // No service worker found. Probably a different app. Reload the page.\n        navigator.serviceWorker.ready.then(registration => {\n          registration.unregister().then(() => {\n            window.location.reload();\n          });\n        });\n      } else {\n        // Service worker found. Proceed as normal.\n        registerValidSW(swUrl);\n      }\n    })\n    .catch(() => {\n      console.log(\n        'No internet connection found. App is running in offline mode.'\n      );\n    });\n}\n\nexport function unregister() {\n  if ('serviceWorker' in navigator) {\n    navigator.serviceWorker.ready.then(registration => {\n      registration.unregister();\n    });\n  }\n}\n"
  },
  {
    "path": "examples/draft-0-10-0/rich/RichEditor.css",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n.RichEditor-root {\n  background: #fff;\n  border: 1px solid #ddd;\n  font-family: 'Georgia', serif;\n  font-size: 14px;\n  padding: 15px;\n}\n\n.RichEditor-editor {\n  border-top: 1px solid #ddd;\n  cursor: text;\n  font-size: 16px;\n  margin-top: 10px;\n}\n\n.RichEditor-editor .public-DraftEditorPlaceholder-root,\n.RichEditor-editor .public-DraftEditor-content {\n  margin: 0 -15px -15px;\n  padding: 15px;\n}\n\n.RichEditor-editor .public-DraftEditor-content {\n  min-height: 100px;\n}\n\n.RichEditor-hidePlaceholder .public-DraftEditorPlaceholder-root {\n  display: none;\n}\n\n.RichEditor-editor .RichEditor-blockquote {\n  border-left: 5px solid #eee;\n  color: #666;\n  font-family: 'Hoefler Text', 'Georgia', serif;\n  font-style: italic;\n  margin: 16px 0;\n  padding: 10px 20px;\n}\n\n.RichEditor-editor .public-DraftStyleDefault-pre {\n  background-color: rgba(0, 0, 0, 0.05);\n  font-family: 'Inconsolata', 'Menlo', 'Consolas', monospace;\n  font-size: 16px;\n  padding: 20px;\n}\n\n.RichEditor-controls {\n  font-family: 'Helvetica', sans-serif;\n  font-size: 14px;\n  margin-bottom: 5px;\n  user-select: none;\n}\n\n.RichEditor-styleButton {\n  color: #999;\n  cursor: pointer;\n  margin-right: 16px;\n  padding: 2px 0;\n  display: inline-block;\n}\n\n.RichEditor-activeButton {\n  color: #5890ff;\n}\n"
  },
  {
    "path": "examples/draft-0-10-0/rich/rich.html",
    "content": "<!--\nCopyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n\nThis file provided by Facebook is for non-commercial testing and evaluation\npurposes only. Facebook reserves all rights not expressly granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\nFACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n-->\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Draft • Rich Text</title>\n    <link rel=\"stylesheet\" href=\"../../../dist/Draft.css\" />\n    <link rel=\"stylesheet\" href=\"RichEditor.css\" />\n    <style>\n      #target { width: 600px; }\n    </style>\n  </head>\n  <body>\n    <div id=\"target\"></div>\n    <script src=\"../../../node_modules/react/umd/react.development.js\"></script>\n    <script src=\"../../../node_modules/react-dom/umd/react-dom.development.js\"></script>\n    <script src=\"../../../node_modules/immutable/dist/immutable.js\"></script>\n    <script src=\"../../../node_modules/es6-shim/es6-shim.js\"></script>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.js\"></script>\n    <script src=\"../../../dist/Draft.js\"></script>\n    <script type=\"text/babel\">\n      'use strict';\n\n      const {Editor, EditorState, RichUtils, getDefaultKeyBinding} = Draft;\n\n      class RichEditorExample extends React.Component {\n        constructor(props) {\n          super(props);\n          this.state = {editorState: EditorState.createEmpty()};\n\n          this.focus = () => this.refs.editor.focus();\n          this.onChange = (editorState) => this.setState({editorState});\n\n          this.handleKeyCommand = this._handleKeyCommand.bind(this);\n          this.mapKeyToEditorCommand = this._mapKeyToEditorCommand.bind(this);\n          this.toggleBlockType = this._toggleBlockType.bind(this);\n          this.toggleInlineStyle = this._toggleInlineStyle.bind(this);\n        }\n\n        _handleKeyCommand(command, editorState) {\n          const newState = RichUtils.handleKeyCommand(editorState, command);\n          if (newState) {\n            this.onChange(newState);\n            return true;\n          }\n          return false;\n        }\n\n        _mapKeyToEditorCommand(e) {\n          if (e.keyCode === 9 /* TAB */) {\n            const newEditorState = RichUtils.onTab(\n              e,\n              this.state.editorState,\n              4, /* maxDepth */\n            );\n            if (newEditorState !== this.state.editorState) {\n              this.onChange(newEditorState);\n            }\n            return;\n          }\n          return getDefaultKeyBinding(e);\n        }\n\n        _toggleBlockType(blockType) {\n          this.onChange(\n            RichUtils.toggleBlockType(\n              this.state.editorState,\n              blockType\n            )\n          );\n        }\n\n        _toggleInlineStyle(inlineStyle) {\n          this.onChange(\n            RichUtils.toggleInlineStyle(\n              this.state.editorState,\n              inlineStyle\n            )\n          );\n        }\n\n        render() {\n          const {editorState} = this.state;\n\n          // If the user changes block type before entering any text, we can\n          // either style the placeholder or hide it. Let's just hide it now.\n          let className = 'RichEditor-editor';\n          var contentState = editorState.getCurrentContent();\n          if (!contentState.hasText()) {\n            if (contentState.getBlockMap().first().getType() !== 'unstyled') {\n              className += ' RichEditor-hidePlaceholder';\n            }\n          }\n\n          return (\n            <div className=\"RichEditor-root\">\n              <BlockStyleControls\n                editorState={editorState}\n                onToggle={this.toggleBlockType}\n              />\n              <InlineStyleControls\n                editorState={editorState}\n                onToggle={this.toggleInlineStyle}\n              />\n              <div className={className} onClick={this.focus}>\n                <Editor\n                  blockStyleFn={getBlockStyle}\n                  customStyleMap={styleMap}\n                  editorState={editorState}\n                  handleKeyCommand={this.handleKeyCommand}\n                  keyBindingFn={this.mapKeyToEditorCommand}\n                  onChange={this.onChange}\n                  placeholder=\"Tell a story...\"\n                  ref=\"editor\"\n                  spellCheck={true}\n                />\n              </div>\n            </div>\n          );\n        }\n      }\n\n      // Custom overrides for \"code\" style.\n      const styleMap = {\n        CODE: {\n          backgroundColor: 'rgba(0, 0, 0, 0.05)',\n          fontFamily: '\"Inconsolata\", \"Menlo\", \"Consolas\", monospace',\n          fontSize: 16,\n          padding: 2,\n        },\n      };\n\n      function getBlockStyle(block) {\n        switch (block.getType()) {\n          case 'blockquote': return 'RichEditor-blockquote';\n          default: return null;\n        }\n      }\n\n      class StyleButton extends React.Component {\n        constructor() {\n          super();\n          this.onToggle = (e) => {\n            e.preventDefault();\n            this.props.onToggle(this.props.style);\n          };\n        }\n\n        render() {\n          let className = 'RichEditor-styleButton';\n          if (this.props.active) {\n            className += ' RichEditor-activeButton';\n          }\n\n          return (\n            <span className={className} onMouseDown={this.onToggle}>\n              {this.props.label}\n            </span>\n          );\n        }\n      }\n\n      const BLOCK_TYPES = [\n        {label: 'H1', style: 'header-one'},\n        {label: 'H2', style: 'header-two'},\n        {label: 'H3', style: 'header-three'},\n        {label: 'H4', style: 'header-four'},\n        {label: 'H5', style: 'header-five'},\n        {label: 'H6', style: 'header-six'},\n        {label: 'Blockquote', style: 'blockquote'},\n        {label: 'UL', style: 'unordered-list-item'},\n        {label: 'OL', style: 'ordered-list-item'},\n        {label: 'Code Block', style: 'code-block'},\n      ];\n\n      const BlockStyleControls = (props) => {\n        const {editorState} = props;\n        const selection = editorState.getSelection();\n        const blockType = editorState\n          .getCurrentContent()\n          .getBlockForKey(selection.getStartKey())\n          .getType();\n\n        return (\n          <div className=\"RichEditor-controls\">\n            {BLOCK_TYPES.map((type) =>\n              <StyleButton\n                key={type.label}\n                active={type.style === blockType}\n                label={type.label}\n                onToggle={props.onToggle}\n                style={type.style}\n              />\n            )}\n          </div>\n        );\n      };\n\n      var INLINE_STYLES = [\n        {label: 'Bold', style: 'BOLD'},\n        {label: 'Italic', style: 'ITALIC'},\n        {label: 'Underline', style: 'UNDERLINE'},\n        {label: 'Monospace', style: 'CODE'},\n      ];\n\n      const InlineStyleControls = (props) => {\n        const currentStyle = props.editorState.getCurrentInlineStyle();\n        \n        return (\n          <div className=\"RichEditor-controls\">\n            {INLINE_STYLES.map((type) =>\n              <StyleButton\n                key={type.label}\n                active={currentStyle.has(type.style)}\n                label={type.label}\n                onToggle={props.onToggle}\n                style={type.style}\n              />\n            )}\n          </div>\n        );\n      };\n\n      ReactDOM.render(\n        <RichEditorExample />,\n        document.getElementById('target')\n      );\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/draft-0-10-0/tex/.babelrc",
    "content": "{\"presets\":[\"@babel/env\"]}\n"
  },
  {
    "path": "examples/draft-0-10-0/tex/js/app.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n'use strict';\n\nimport TeXEditorExample from './components/TeXEditorExample';\nimport React from 'react';\nimport ReactDOM from 'react-dom';\n\nReactDOM.render(\n  <TeXEditorExample />,\n  document.getElementById('target'),\n);\n"
  },
  {
    "path": "examples/draft-0-10-0/tex/js/components/TeXBlock.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n'use strict';\n\nimport katex from 'katex';\nimport React from 'react';\n\nclass KatexOutput extends React.Component {\n  _update() {\n    katex.render(\n      this.props.content,\n      this.refs.container,\n      {displayMode: true},\n    );\n  }\n\n  componentDidMount() {\n    this._update();\n  }\n\n  componentDidUpdate(prevProps, prevState) {\n    if (prevProps.content !== this.props.content) {\n      this._update();\n    }\n  }\n\n  render() {\n    return <div ref=\"container\" onClick={this.props.onClick} />;\n  }\n}\n\nexport default class TeXBlock extends React.Component {\n  constructor(props) {\n    super(props);\n    this.state = {editMode: false};\n\n    this._onClick = () => {\n      if (this.state.editMode) {\n        return;\n      }\n\n      this.setState({\n        editMode: true,\n        texValue: this._getValue(),\n      }, () => {\n        this._startEdit();\n      });\n    };\n\n    this._onValueChange = evt => {\n      var value = evt.target.value;\n      var invalid = false;\n      try {\n        katex.__parse(value);\n      } catch (e) {\n        invalid = true;\n      } finally {\n        this.setState({\n          invalidTeX: invalid,\n          texValue: value,\n        });\n      }\n    };\n\n    this._save = () => {\n      var entityKey = this.props.block.getEntityAt(0);\n      var newContentState = this.props.contentState.mergeEntityData(\n        entityKey,\n        {content: this.state.texValue},\n      );\n      this.setState({\n        invalidTeX: false,\n        editMode: false,\n        texValue: null,\n      }, this._finishEdit.bind(this, newContentState));\n    };\n\n    this._remove = () => {\n      this.props.blockProps.onRemove(this.props.block.getKey());\n    };\n    this._startEdit = () => {\n      this.props.blockProps.onStartEdit(this.props.block.getKey());\n    };\n    this._finishEdit = (newContentState) => {\n      this.props.blockProps.onFinishEdit(\n        this.props.block.getKey(),\n        newContentState,\n      );\n    };\n  }\n\n  _getValue() {\n    return this.props.contentState\n      .getEntity(this.props.block.getEntityAt(0))\n      .getData()['content'];\n  }\n\n  render() {\n    var texContent = null;\n    if (this.state.editMode) {\n      if (this.state.invalidTeX) {\n        texContent = '';\n      } else {\n        texContent = this.state.texValue;\n      }\n    } else {\n      texContent = this._getValue();\n    }\n\n    var className = 'TeXEditor-tex';\n    if (this.state.editMode) {\n      className += ' TeXEditor-activeTeX';\n    }\n\n    var editPanel = null;\n    if (this.state.editMode) {\n      var buttonClass = 'TeXEditor-saveButton';\n      if (this.state.invalidTeX) {\n        buttonClass += ' TeXEditor-invalidButton';\n      }\n\n      editPanel =\n        <div className=\"TeXEditor-panel\">\n          <textarea\n            className=\"TeXEditor-texValue\"\n            onChange={this._onValueChange}\n            ref=\"textarea\"\n            value={this.state.texValue}\n          />\n          <div className=\"TeXEditor-buttons\">\n            <button\n              className={buttonClass}\n              disabled={this.state.invalidTeX}\n              onClick={this._save}>\n              {this.state.invalidTeX ? 'Invalid TeX' : 'Done'}\n            </button>\n            <button className=\"TeXEditor-removeButton\" onClick={this._remove}>\n              Remove\n            </button>\n          </div>\n        </div>;\n    }\n\n    return (\n      <div className={className}>\n        <KatexOutput content={texContent} onClick={this._onClick} />\n        {editPanel}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "examples/draft-0-10-0/tex/js/components/TeXEditorExample.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n'use strict';\n\nimport Draft from 'draft-js';\nimport {Map} from 'immutable';\nimport React from 'react';\n\nimport TeXBlock from './TeXBlock';\nimport {content} from '../data/content';\nimport {insertTeXBlock} from '../modifiers/insertTeXBlock';\nimport {removeTeXBlock} from '../modifiers/removeTeXBlock';\n\nvar {Editor, EditorState, RichUtils} = Draft;\n\nexport default class TeXEditorExample extends React.Component {\n  constructor(props) {\n    super(props);\n    this.state = {\n      editorState: EditorState.createWithContent(content),\n      liveTeXEdits: Map(),\n    };\n\n    this._blockRenderer = (block) => {\n      if (block.getType() === 'atomic') {\n        return {\n          component: TeXBlock,\n          editable: false,\n          props: {\n            onStartEdit: (blockKey) => {\n              var {liveTeXEdits} = this.state;\n              this.setState({liveTeXEdits: liveTeXEdits.set(blockKey, true)});\n            },\n            onFinishEdit: (blockKey, newContentState) => {\n              var {liveTeXEdits} = this.state;\n              this.setState({\n                liveTeXEdits: liveTeXEdits.remove(blockKey),\n                editorState:EditorState.createWithContent(newContentState),\n              });\n            },\n            onRemove: (blockKey) => this._removeTeX(blockKey),\n          },\n        };\n      }\n      return null;\n    };\n\n    this._focus = () => this.refs.editor.focus();\n    this._onChange = (editorState) => this.setState({editorState});\n\n    this._handleKeyCommand = (command, editorState) => {\n      var newState = RichUtils.handleKeyCommand(editorState, command);\n      if (newState) {\n        this._onChange(newState);\n        return true;\n      }\n      return false;\n    };\n\n    this._removeTeX = (blockKey) => {\n      var {editorState, liveTeXEdits} = this.state;\n      this.setState({\n        liveTeXEdits: liveTeXEdits.remove(blockKey),\n        editorState: removeTeXBlock(editorState, blockKey),\n      });\n    };\n\n    this._insertTeX = () => {\n      this.setState({\n        liveTeXEdits: Map(),\n        editorState: insertTeXBlock(this.state.editorState),\n      });\n    };\n  }\n\n  /**\n   * While editing TeX, set the Draft editor to read-only. This allows us to\n   * have a textarea within the DOM.\n   */\n  render() {\n    return (\n      <div className=\"TexEditor-container\">\n        <div className=\"TeXEditor-root\">\n          <div className=\"TeXEditor-editor\" onClick={this._focus}>\n            <Editor\n              blockRendererFn={this._blockRenderer}\n              editorState={this.state.editorState}\n              handleKeyCommand={this._handleKeyCommand}\n              onChange={this._onChange}\n              placeholder=\"Start a document...\"\n              readOnly={this.state.liveTeXEdits.count()}\n              ref=\"editor\"\n              spellCheck={true}\n            />\n          </div>\n        </div>\n        <button onClick={this._insertTeX} className=\"TeXEditor-insert\">\n          {'Insert new TeX'}\n        </button>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "examples/draft-0-10-0/tex/js/data/content.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\nimport {convertFromRaw} from 'draft-js';\n\nvar rawContent = {\n  blocks: [\n    {\n      text: 'This is a Draft-based editor that supports TeX rendering.',\n      type: 'unstyled',\n    },\n    {\n      text: '',\n      type: 'unstyled',\n    },\n    {\n      text: (\n        'Each TeX block below is represented as a DraftEntity object and ' +\n        'rendered using Khan Academy\\'s KaTeX library.'\n      ),\n      type: 'unstyled',\n    },\n    {\n      text: '',\n      type: 'unstyled',\n    },\n    {\n      text: 'Click any TeX block to edit.',\n      type: 'unstyled',\n    },\n    {\n      text: ' ',\n      type: 'atomic',\n      entityRanges: [{offset: 0, length: 1, key: 'first'}],\n    },\n    {\n      text: 'You can also insert a new TeX block at the cursor location.',\n      type: 'unstyled',\n    },\n  ],\n\n  entityMap: {\n    first: {\n      type: 'TOKEN',\n      mutability: 'IMMUTABLE',\n      data: {\n        content: (\n          '\\\\left( \\\\sum_{k=1}^n a_k b_k \\\\right)^{\\\\!\\\\!2} \\\\leq\\n' +\n          '\\\\left( \\\\sum_{k=1}^n a_k^2 \\\\right)\\n' +\n          '\\\\left( \\\\sum_{k=1}^n b_k^2 \\\\right)'\n        ),\n      },\n    },\n  },\n};\n\nexport var content = convertFromRaw(rawContent);\n"
  },
  {
    "path": "examples/draft-0-10-0/tex/js/modifiers/insertTeXBlock.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n'use strict';\n\nimport {\n  AtomicBlockUtils,\n  EditorState,\n} from 'draft-js';\n\nlet count = 0;\nconst examples = [\n  '\\\\int_a^bu\\\\frac{d^2v}{dx^2}\\\\,dx\\n' +\n  '=\\\\left.u\\\\frac{dv}{dx}\\\\right|_a^b\\n' +\n  '-\\\\int_a^b\\\\frac{du}{dx}\\\\frac{dv}{dx}\\\\,dx',\n\n  'P(E) = {n \\\\choose k} p^k (1-p)^{ n-k} ',\n\n  '\\\\tilde f(\\\\omega)=\\\\frac{1}{2\\\\pi}\\n' +\n  '\\\\int_{-\\\\infty}^\\\\infty f(x)e^{-i\\\\omega x}\\\\,dx',\n\n  '\\\\frac{1}{(\\\\sqrt{\\\\phi \\\\sqrt{5}}-\\\\phi) e^{\\\\frac25 \\\\pi}} =\\n' +\n  '1+\\\\frac{e^{-2\\\\pi}} {1+\\\\frac{e^{-4\\\\pi}} {1+\\\\frac{e^{-6\\\\pi}}\\n' +\n  '{1+\\\\frac{e^{-8\\\\pi}} {1+\\\\ldots} } } }',\n];\n\nexport function insertTeXBlock(editorState) {\n  const contentState = editorState.getCurrentContent();\n  const nextFormula = count++ % examples.length;\n  const contentStateWithEntity = contentState.createEntity(\n    'TOKEN',\n    'IMMUTABLE',\n    {content: examples[nextFormula]},\n  );\n  const entityKey = contentStateWithEntity.getLastCreatedEntityKey();\n  const newEditorState = EditorState.set(\n    editorState,\n    {currentContent: contentStateWithEntity},\n  );\n  return AtomicBlockUtils.insertAtomicBlock(newEditorState, entityKey, ' ');\n}\n"
  },
  {
    "path": "examples/draft-0-10-0/tex/js/modifiers/removeTeXBlock.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n'use strict';\n\nimport {EditorState, Modifier, SelectionState} from 'draft-js';\n\nexport function removeTeXBlock(editorState, blockKey) {\n  var content = editorState.getCurrentContent();\n  var block = content.getBlockForKey(blockKey);\n\n  var targetRange = new SelectionState({\n    anchorKey: blockKey,\n    anchorOffset: 0,\n    focusKey: blockKey,\n    focusOffset: block.getLength(),\n  });\n\n  var withoutTeX = Modifier.removeRange(content, targetRange, 'backward');\n  var resetBlock = Modifier.setBlockType(\n    withoutTeX,\n    withoutTeX.getSelectionAfter(),\n    'unstyled',\n  );\n\n  var newState = EditorState.push(editorState, resetBlock, 'remove-range');\n  return EditorState.forceSelection(newState, resetBlock.getSelectionAfter());\n}\n"
  },
  {
    "path": "examples/draft-0-10-0/tex/package.json",
    "content": "{\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"babel-node ./server.js\"\n  },\n  \"dependencies\": {\n    \"@babel/core\": \"^7.12.9\",\n    \"@babel/preset-env\": \"^7.12.7\",\n    \"@babel/preset-react\": \"^7.12.7\",\n    \"babel-loader\": \"^8.2.2\",\n    \"draft-js\": \"file:../../../\",\n    \"express\": \"^4.17.1\",\n    \"immutable\": \"^3.8.2\",\n    \"katex\": \"^0.7.0\",\n    \"react\": \"file:../../../node_modules/react\",\n    \"react-dom\": \"file:../../../node_modules/react-dom\",\n    \"webpack\": \"^5.10.0\",\n    \"webpack-dev-server\": \"^3.11.0\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.12.8\",\n    \"@babel/node\": \"^7.12.6\"\n  }\n}\n"
  },
  {
    "path": "examples/draft-0-10-0/tex/public/TeXEditor.css",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n.TeXEditor-root {\n  font-family: 'Century Schoolbook', serif;\n  -webkit-font-smoothing: antialiased;\n  margin: 40px auto;\n  width: 900px;\n}\n\n.TeXEditor-editor {\n  cursor: text;\n  font-size: 18px;\n  min-height: 40px;\n  padding: 30px;\n}\n\n.TeXEditor-button {\n  margin-top: 10px;\n  text-align: center;\n}\n\n.TeXEditor-handle {\n  color: rgba(98, 177, 254, 1);\n  direction: ltr;\n  unicode-bidi: bidi-override;\n}\n\n.TeXEditor-hashtag {\n  color: rgba(95, 184, 138, 1);\n}\n\n.TeXEditor-tex {\n  background-color: #fff;\n  cursor: pointer;\n  margin: 20px auto;\n  padding: 20px;\n  -webkit-transition: background-color 0.2s fade-in-out;\n  user-select: none;\n  -webkit-user-select: none;\n}\n\n.TeXEditor-activeTeX {\n  color: #888;\n}\n\n.TeXEditor-panel {\n  font-family: 'Helvetica', sans-serif;\n  font-weight: 200;\n}\n\n.TeXEditor-panel .TeXEditor-texValue {\n  border: 1px solid #e1e1e1;\n  display: block;\n  font-family: 'Inconsolata', 'Menlo', monospace;\n  font-size: 14px;\n  height: 110px;\n  margin: 20px auto 10px;\n  outline: none;\n  padding: 14px;\n  resize: none;\n  -webkit-box-sizing: border-box;\n  width: 500px;\n}\n\n.TeXEditor-buttons {\n  text-align: center;\n}\n\n.TeXEditor-saveButton,\n.TeXEditor-removeButton {\n  background-color: #fff;\n  border: 1px solid #0a0;\n  cursor: pointer;\n  font-family: 'Helvetica', 'Arial', sans-serif;\n  font-size: 16px;\n  font-weight: 200;\n  margin: 10px auto;\n  padding: 6px;\n  -webkit-border-radius: 3px;\n  width: 100px;\n}\n\n.TeXEditor-removeButton {\n  border-color: #aaa;\n  color: #999;\n  margin-left: 8px;\n}\n\n.TeXEditor-invalidButton {\n  background-color: #eee;\n  border-color: #a00;\n  color: #666;\n}\n\n.TeXEditor-insert {\n  background-color: #f1f1f1;\n  border: 1px solid #ccc;\n  border-radius: 3px;\n  bottom: 30px;\n  position: fixed;\n  right: 30px;\n}\n"
  },
  {
    "path": "examples/draft-0-10-0/tex/public/index.html",
    "content": "<!--\nCopyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n\nThis file provided by Facebook is for non-commercial testing and evaluation\npurposes only. Facebook reserves all rights not expressly granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\nFACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n-->\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Draft • TeX</title>\n    <link rel=\"stylesheet\" href=\"TeXEditor.css\" />\n    <link rel=\"stylesheet\" href=\"node_modules/draft-js/dist/Draft.css\" />\n    <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/katex.min.css\">\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.34.4/es6-shim.min.js\"></script>\n  </head>\n  <body>\n    <div id=\"target\"></div>\n    <script src=\"http://localhost:3000/webpack-dev-server.js\"></script>\n    <script src=\"js/app.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/draft-0-10-0/tex/readme.md",
    "content": "# TEX\n\nThe TeX editor in the Draft repository provides a live example of custom block rendering, with TeX syntax translated on the fly into editable embedded formula rendering via the [KaTeX library](https://khan.github.io/KaTeX/).\n\n### How to run\n\n```bash\n# in draft-js folder\nyarn\ncd examples/draft-0-10-0/tex\nyarn\nyarn start\n```\n\nwhich will open a server listening on [http://localhost:3000](http://localhost:3000)\n"
  },
  {
    "path": "examples/draft-0-10-0/tex/server.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\nimport express from 'express';\nimport path from 'path';\nimport webpack from 'webpack';\nimport WebpackDevServer from 'webpack-dev-server';\n\nconst APP_PORT = 3000;\n\n// Serve the TeX Editor app\nvar compiler = webpack({\n  entry: path.resolve(__dirname, 'js', 'app.js'),\n  module: {\n    rules: [\n      {\n        test: /\\.js$/,\n        exclude: /node_modules/,\n        loader: 'babel-loader',\n        options: {\n          presets: ['@babel/env', '@babel/react'],\n        },\n      },\n    ],\n  },\n  output: {filename: 'app.js', path: '/'},\n  mode: 'development',\n});\nvar app = new WebpackDevServer(compiler, {\n  contentBase: '/public/',\n  publicPath: '/js/',\n  stats: {colors: true},\n});\n// Serve static resources\napp.use('/', express.static('public'));\napp.use('/node_modules', express.static('node_modules'));\napp.listen(APP_PORT, () => {\n  console.log(`TeX Editor is now running on http://localhost:${APP_PORT}`);\n});\n"
  },
  {
    "path": "examples/draft-0-10-0/tweet/tweet.html",
    "content": "<!--\nCopyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n\nThis file provided by Facebook is for non-commercial testing and evaluation\npurposes only. Facebook reserves all rights not expressly granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\nFACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n-->\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Draft • Decorators</title>\n    <link rel=\"stylesheet\" href=\"../../../dist/Draft.css\" />\n  </head>\n  <body>\n    <div id=\"target\"></div>\n    <script src=\"../../../node_modules/react/umd/react.development.js\"></script>\n    <script src=\"../../../node_modules/react-dom/umd/react-dom.development.js\"></script>\n    <script src=\"../../../node_modules/immutable/dist/immutable.js\"></script>\n    <script src=\"../../../node_modules/es6-shim/es6-shim.js\"></script>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.js\"></script>\n    <script src=\"../../../dist/Draft.js\"></script>\n    <script type=\"text/babel\">\n      'use strict';\n\n      const {CompositeDecorator, Editor, EditorState} = Draft;\n\n      class TweetEditorExample extends React.Component {\n        constructor() {\n          super();\n          const compositeDecorator = new CompositeDecorator([\n            {\n              strategy: handleStrategy,\n              component: HandleSpan,\n            },\n            {\n              strategy: hashtagStrategy,\n              component: HashtagSpan,\n            },\n          ]);\n\n          this.state = {\n            editorState: EditorState.createEmpty(compositeDecorator),\n          };\n\n          this.focus = () => this.refs.editor.focus();\n          this.onChange = (editorState) => this.setState({editorState});\n          this.logState = () => console.log(this.state.editorState.toJS());\n        }\n\n        render() {\n          return (\n            <div style={styles.root}>\n              <div style={styles.editor} onClick={this.focus}>\n                <Editor\n                  editorState={this.state.editorState}\n                  onChange={this.onChange}\n                  placeholder=\"Write a tweet...\"\n                  ref=\"editor\"\n                  spellCheck={true}\n                />\n              </div>\n              <input\n                onClick={this.logState}\n                style={styles.button}\n                type=\"button\"\n                value=\"Log State\"\n              />\n            </div>\n          );\n        }\n      }\n\n      /**\n       * Super simple decorators for handles and hashtags, for demonstration\n       * purposes only. Don't reuse these regexes.\n       */\n      const HANDLE_REGEX = /@[\\w]+/g;\n      const HASHTAG_REGEX = /#[\\w\\u0590-\\u05ff]+/g;\n\n      function handleStrategy(contentBlock, callback, contentState) {\n        findWithRegex(HANDLE_REGEX, contentBlock, callback);\n      }\n\n      function hashtagStrategy(contentBlock, callback, contentState) {\n        findWithRegex(HASHTAG_REGEX, contentBlock, callback);\n      }\n\n      function findWithRegex(regex, contentBlock, callback) {\n        const text = contentBlock.getText();\n        let matchArr, start;\n        while ((matchArr = regex.exec(text)) !== null) {\n          start = matchArr.index;\n          callback(start, start + matchArr[0].length);\n        }\n      }\n\n      const HandleSpan = (props) => {\n        return (\n          <span\n            style={styles.handle}\n            data-offset-key={props.offsetKey}\n          >\n            {props.children}\n          </span>\n        );\n      };\n\n      const HashtagSpan = (props) => {\n        return (\n          <span\n            style={styles.hashtag}\n            data-offset-key={props.offsetKey}\n          >\n            {props.children}\n          </span>\n        );\n      };\n\n      const styles = {\n        root: {\n          fontFamily: '\\'Helvetica\\', sans-serif',\n          padding: 20,\n          width: 600,\n        },\n        editor: {\n          border: '1px solid #ddd',\n          cursor: 'text',\n          fontSize: 16,\n          minHeight: 40,\n          padding: 10,\n        },\n        button: {\n          marginTop: 10,\n          textAlign: 'center',\n        },\n        handle: {\n          color: 'rgba(98, 177, 254, 1.0)',\n          direction: 'ltr',\n          unicodeBidi: 'bidi-override',\n        },\n        hashtag: {\n          color: 'rgba(95, 184, 138, 1.0)',\n        },\n      };\n\n      ReactDOM.render(\n        <TweetEditorExample />,\n        document.getElementById('target')\n      );\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/draft-0-10-0/universal/.babelrc",
    "content": "{ \"presets\": [\"@babel/preset-react\"] }"
  },
  {
    "path": "examples/draft-0-10-0/universal/client.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n'use strict';\n\nvar React = require('react');\nvar ReactDom = require('react-dom');\n\nvar SimpleEditor = require('./editor.js').SimpleEditor;\n\nReactDom.render(<SimpleEditor />, document.getElementById('react-content'));\n"
  },
  {
    "path": "examples/draft-0-10-0/universal/editor.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n'use strict';\n\nconst Draft = require('draft-js');\nconst React = require('react');\n\nclass SimpleEditor extends React.Component {\n  constructor(props) {\n    super(props);\n\n    this.state = {\n      editorState: Draft.EditorState.createWithContent(emptyContentState),\n    };\n    this.onChange = (editorState) => this.setState({editorState});\n  }\n  render() {\n    const Editor = Draft.Editor;\n    const editorState = this.state.editorState;\n    return (\n      <div style={{border: '1px solid black', padding: 10}}>\n        <Editor\n          placeholder=\"Write something!\"\n          editorKey=\"foobaz\"\n          editorState={editorState}\n          onChange={this.onChange}\n        />\n      </div>\n    );\n  }\n}\nmodule.exports = {\n  SimpleEditor: SimpleEditor,\n};\n\nconst emptyContentState = Draft.convertFromRaw({\n  entityMap: {},\n  blocks: [\n    {\n      text: '',\n      key: 'foo',\n      type: 'unstyled',\n      entityRanges: [],\n    },\n  ],\n});\n"
  },
  {
    "path": "examples/draft-0-10-0/universal/index.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.\n *\n * This file provided by Facebook is for non-commercial testing and evaluation\n * purposes only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n'use strict';\n\nvar React = require('react');\nvar ReactDOMServer = require('react-dom/server');\n\nvar SimpleEditor = require('./editor.js').SimpleEditor;\n\nvar express = require('express');\n\nvar app = express();\n\napp.use('/static', express.static('static'));\n\napp.get('/', (req, res) => {\n  const rendered = ReactDOMServer.renderToString(<SimpleEditor />);\n  const page = `<!doctype html>\n<html>\n  <body>\n    <div id=\"react-content\">${ rendered }</div>\n    <script src=\"/static/bundle.js\"></script>\n  </body>\n</html>\n  `;\n  res.send(page);\n});\n\napp.listen(3003);\nconsole.log('app now listening at http://localhost:3003');\n"
  },
  {
    "path": "examples/draft-0-10-0/universal/package.json",
    "content": "{\n  \"name\": \"universal\",\n  \"version\": \"1.0.0\",\n  \"main\": \"index.js\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"draft-js\": \"file:../../../\",\n    \"express\": \"^4.17.1\",\n    \"immutable\": \"^3.8.2\",\n    \"react\": \"file:../../../node_modules/react\",\n    \"react-dom\": \"file:../../../node_modules/react-dom\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.12.10\",\n    \"@babel/core\": \"^7.12.10\",\n    \"@babel/node\": \"^7.12.10\",\n    \"@babel/preset-react\": \"^7.12.10\",\n    \"babelify\": \"^10.0.0\",\n    \"browserify\": \"^17.0.0\"\n  },\n  \"scripts\": {\n    \"build\": \"browserify client.js -t babelify -o static/bundle.js\",\n    \"start\": \"babel-node index.js\",\n    \"demo\": \"npm run build && npm run start\"\n  }\n}\n"
  },
  {
    "path": "examples/draft-0-10-0/universal/readme.md",
    "content": "# Universal rendering\n\nDraft is well suited for universal (isomorphic) rendering contexts:\n\nHere, we have three files:\n\n* editor.js\n  A basic draftjs editor exported as `<SimpleEditor />`\n* client.js\n  A basic clientside entrypoint that clientside renders the index page route's logic into a `#react-content` div.\n* index.js\n  A basic express server that prerenders a <SimpleEditor /> in the `#react-content` div\n\nyou can run this by first building draft-js and then installing this demo's dependencies\n\n```bash\n# in draft-js folder\nyarn\npushd examples/draft-0-10-0/universal\nyarn\n```\n\nthen, run\n\n`npm run demo`\n\nwhich will open a server listening on [http://localhost:3003](http://localhost:3003)\n"
  },
  {
    "path": "gulpfile.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n'use strict';\n\nconst packageData = require('./package.json');\nconst moduleMap = require('./scripts/module-map');\nconst fbjsConfigurePreset = require('babel-preset-fbjs/configure');\nconst del = require('del');\nconst gulpCheckDependencies = require('fbjs-scripts/gulp/check-dependencies');\nconst gulp = require('gulp');\nconst babel = require('gulp-babel');\nconst cleanCSS = require('gulp-clean-css');\nconst concatCSS = require('gulp-concat-css');\nconst derequire = require('gulp-derequire');\nconst flatten = require('gulp-flatten');\nconst header = require('gulp-header');\nconst gulpif = require('gulp-if');\nconst rename = require('gulp-rename');\nconst gulpUtil = require('gulp-util');\nconst StatsPlugin = require('stats-webpack-plugin');\nconst through = require('through2');\nconst UglifyJsPlugin = require('uglifyjs-webpack-plugin');\nconst webpackStream = require('webpack-stream');\n\nconst paths = {\n  dist: 'dist',\n  lib: 'lib',\n  src: [\n    'src/**/*.js',\n    '!src/**/__tests__/**/*.js',\n    '!src/**/__mocks__/**/*.js',\n  ],\n  css: ['src/**/*.css'],\n};\n\nconst babelOptsJS = {\n  presets: [\n    fbjsConfigurePreset({\n      stripDEV: true,\n      rewriteModules: {map: moduleMap},\n    }),\n  ],\n  plugins: [\n    require('@babel/plugin-proposal-nullish-coalescing-operator'),\n    require('@babel/plugin-proposal-optional-chaining'),\n    require('@babel/plugin-proposal-optional-catch-binding'),\n  ],\n};\n\nconst babelOptsFlow = {\n  presets: [\n    fbjsConfigurePreset({\n      target: 'flow',\n      rewriteModules: {map: moduleMap},\n    }),\n  ],\n  plugins: [\n    require('@babel/plugin-proposal-nullish-coalescing-operator'),\n    require('@babel/plugin-proposal-optional-chaining'),\n    require('@babel/plugin-proposal-optional-catch-binding'),\n  ],\n};\n\nvar COPYRIGHT_HEADER = `/**\n * Draft v<%= version %>\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n`;\n\nconst buildDist = opts => {\n  const webpackOpts = {\n    externals: {\n      immutable: {\n        root: 'Immutable',\n        commonjs2: 'immutable',\n        commonjs: 'immutable',\n        amd: 'immutable',\n      },\n      react: {\n        root: 'React',\n        commonjs2: 'react',\n        commonjs: 'react',\n        amd: 'react',\n      },\n      'react-dom': {\n        root: 'ReactDOM',\n        commonjs2: 'react-dom',\n        commonjs: 'react-dom',\n        amd: 'react-dom',\n      },\n    },\n    output: {\n      filename: opts.output,\n      libraryTarget: 'umd',\n      library: 'Draft',\n    },\n    plugins: [\n      new webpackStream.webpack.DefinePlugin({\n        'process.env.NODE_ENV': JSON.stringify(\n          opts.debug ? 'development' : 'production',\n        ),\n      }),\n      new webpackStream.webpack.LoaderOptionsPlugin({\n        debug: opts.debug,\n      }),\n      new StatsPlugin(`../meta/bundle-size-stats/${opts.output}.json`, {\n        chunkModules: true,\n      }),\n    ],\n  };\n  if (!opts.debug) {\n    webpackOpts.plugins.push(new UglifyJsPlugin());\n  }\n  const wpStream = webpackStream(webpackOpts, null, function(err, stats) {\n    if (err) {\n      throw new gulpUtil.PluginError('webpack', err);\n    }\n    if (stats.compilation.errors.length) {\n      gulpUtil.log('webpack', '\\n' + stats.toString({colors: true}));\n    }\n  });\n  return wpStream;\n};\n\n/**************** Tasks *****************/\n\n// Builds the CSS\nexports.css = function css() {\n  return (\n    gulp\n      .src(paths.css)\n      .pipe(\n        through.obj(function(file, encoding, callback) {\n          const contents = file.contents.toString();\n          let replaced = contents.replace(\n            // Regex based on MakeHasteCssModuleTransform: ignores comments,\n            // strings, and URLs\n            /\\/\\*.*?\\*\\/|'(?:\\\\.|[^'])*'|\"(?:\\\\.|[^\"])*\"|url\\([^)]*\\)|(\\.(?:public\\/)?[\\w-]*\\/{1,2}[\\w-]+)/g,\n            function(match, cls) {\n              if (cls) {\n                return cls.replace(/\\//g, '-');\n              } else {\n                return match;\n              }\n            },\n          );\n          replaced = replaced.replace(\n            // MakeHasteCssVariablesTransform\n            /\\bvar\\(([\\w-]+)\\)/g,\n            function(match, name) {\n              const vars = {\n                'fig-secondary-text': '#9197a3',\n                'fig-light-20': '#bdc1c9',\n              };\n              if (vars[name]) {\n                return vars[name];\n              } else {\n                throw new Error('Unknown CSS variable ' + name);\n              }\n            },\n          );\n          file.contents = Buffer.from(replaced);\n          callback(null, file);\n        }),\n      )\n      .pipe(concatCSS('Draft.css'))\n      // Avoid rewriting rules *just in case*, just compress\n      .pipe(cleanCSS({advanced: false}))\n      .pipe(header(COPYRIGHT_HEADER, {version: packageData.version}))\n      .pipe(gulp.dest(paths.dist))\n  );\n};\n\n// Cleans artifacts\nexports.clean = function clean() {\n  return del([paths.dist, paths.lib]);\n};\n\n// Transforms modules\nexports.modules = function modules() {\n  return gulp\n    .src(paths.src)\n    .pipe(babel(babelOptsJS))\n    .pipe(flatten())\n    .pipe(gulp.dest(paths.lib));\n};\n\n// Outputs built flow files\nexports.flow = function flow() {\n  return gulp\n    .src(paths.src)\n    .pipe(babel(babelOptsFlow))\n    .pipe(flatten())\n    .pipe(rename({extname: '.js.flow'}))\n    .pipe(gulp.dest(paths.lib));\n};\n\n// Builds for development\nexports.dist = gulp.series(exports.modules, exports.css, function outputDist() {\n  return gulp\n    .src('./lib/Draft.js')\n    .pipe(\n      buildDist({\n        debug: true,\n        output: 'Draft.js',\n      }),\n    )\n    .pipe(derequire())\n    .pipe(\n      gulpif('*.js', header(COPYRIGHT_HEADER, {version: packageData.version})),\n    )\n    .pipe(gulp.dest(paths.dist));\n});\n\n// Builds for production\nexports.dist_min = gulp.series(exports.modules, function outputDistMin() {\n  return gulp\n    .src('./lib/Draft.js')\n    .pipe(\n      buildDist({\n        debug: false,\n        output: 'Draft.min.js',\n      }),\n    )\n    .pipe(\n      gulpif('*.js', header(COPYRIGHT_HEADER, {version: packageData.version})),\n    )\n    .pipe(gulp.dest(paths.dist));\n});\n\n// Checks for \"wrong\" dependencies (file://, for example).\nexports.check_dependencies = function check_dependencies() {\n  return gulp.src('package.json').pipe(gulpCheckDependencies());\n};\n\n// Watches to build modules\nexports.watch = function watch() {\n  gulp.watch(paths.src, exports.modules);\n};\n\n// Watches to build dev artifact\nexports.dev = function dev() {\n  gulp.watch(paths.src, exports.dist);\n};\n\n// Builds everything\nexports.default = gulp.series(\n  exports.check_dependencies,\n  exports.clean,\n  gulp.parallel(exports.modules, exports.flow),\n  gulp.parallel(exports.dist, exports.dist_min),\n);\n"
  },
  {
    "path": "meta/meeting-notes/2017-02-10-weekly-meeting.md",
    "content": "# Draft.js Weekly 2/10/17\n\n* (again) Can we transfer the draftjs.com (http://draftjs.com/) domain to daniel lo nigro? (question for isaac?)\n    * (https://github.com/facebook/draft-js/issues/317)\n* API Breaking Changes: when would we make them?\n    * For comparison, React's guidelines (https://facebook.github.io/react/contributing/design-principles.html#stability) are:\n        * Usually they avoid changing APIs and core behaviors\n        * Changes will have a clear, and preferably automated, migration path\n        * When deprecating a pattern, these steps will be followed:\n            * Support both initially, with deprecation warnings\n            * Test the change internally first at FB\n            * See if it makes sense internally before adding to open source\n            * Deprecate with warnings in one version, then fully break in the next major version\n            * Write a codemod if there is repetetive manual work to upgrade\n    * **After agreeing on a policy we will post this**\n    * Proposal: Similar approach to React, but automated upgrade less important because fewer callsites\n* Meeting notes go up on github now! Flarnie will sanitize and post them after the weekly meeting.\n    * Someone should update our 'contributing' document to mention the meeting notes, like React's docs: https://facebook.github.io/react/contributing/how-to-contribute.html#meeting-notes\n* Upcoming release of v0.11.0@next\n* Tool for debugging/understanding events: https://dvcs.w3.org/hg/d4e/raw-file/tip/key-event-test.html\n\n**Last Week's Action Items:**\n\n* DONE: See how React.js, Relay, and Redux surfaces their roadmaps (Flarnie)\n* DONE: Releasing roadmap\n\n**Action items for next week:**\n\n* Post statement about policy for API breaking changes (Flarnie)\n"
  },
  {
    "path": "meta/meeting-notes/2017-02-17-weekly-meeting.md",
    "content": "# Draft.js Weekly 2/17/17\n\n* (again) Can we transfer the draftjs.com (http://draftjs.com/) domain to daniel lo nigro? (question for isaac?)\n    * (https://github.com/facebook/draft-js/issues/317)\n\n* Android/mobile web support update (flarnie)\n\n**Last Week's Action Items:**\n* DONE: Post statement about policy for API breaking changes (flarnie)\n\n**Action items for next week:**\n* Add these meeting notes in 'meta' directory (tylercraft or flarnie)\n* Release v0.11.0@next (tylercraft)\n* Create PRs for misc. Android bug fixes being tested internally (flarnie)\n* Tasks related to internal FB updates for v0.10.0 syntax changes (flarnie)\n\n"
  },
  {
    "path": "meta/meeting-notes/2017-02-24-weekly-meeting.md",
    "content": "# Draft.js Weekly 2/17/17\n\n* Updates on ongoing projects\n    * v0.10.0 and v0.11.0@next releases\n        * when publishing v.11@next to npm use '—tag next' to make sure it doesn't become the default\n        * waiting on windows testing\n    * Mobile web support\n        * still testing fixes internally\n        * continued improvements in progress\n    * Tree data structure refactor\n        * still waiting to come back to this\n\n**Last Week's Action Items:**\n\n* Basically same as this week's\n\n**Action items for next week:**\n\n* Add these meeting notes in 'meta' directory (flarnie)\n* Release v0.11.0@next (tylercraft)\n* Create PRs for misc. Android bug fixes being tested internally (flarnie)\n* Supervise remaining internal FB tasks related to v0.10.0 API change (flarnie)\n"
  },
  {
    "path": "meta/meeting-notes/2017-03-10-weekly-meeting.md",
    "content": "# Draft.js Weekly 3/10/17\n\n* Android/mobile web support update (@mmmoussa)\n  * Working on two more improvements related to token deletion and backspacing\n* Testing of the v0.11.0@alpha branch is blocked by an IE/Edge bug with the\n  examples - https://github.com/facebook/draft-js/issues/1062\n\n**Last Week's Action Items:**\n* DONE: create branch for v0.11.0 alpha release (@tylerc)\n* DONE: Create PRs for misc. Android bug fixes being tested internally (@flarnie)\n\n**Action items for next week:**\n* Open issues and PRs for android related improvements (@mmmoussa)\n* Add these meeting notes in 'meta' directory (@flarnie)\n* Find fix for #1062 and test v0.11.0@next in IE/Edge (@flarnie)\n* Release v0.11.0@next; blocked for now (@tylercraft)\n* Tasks related to internal FB updates for v0.10.0 syntax changes (@flarnie)\n\n"
  },
  {
    "path": "meta/meeting-notes/2017-03-17-weekly-meeting.md",
    "content": "# Draft.js Weekly 3/17/17\n\nDiscussed https://github.com/facebook/draft-js/pull/1067\n"
  },
  {
    "path": "meta/meeting-notes/2017-03-24-weekly-meeting.md",
    "content": "# Draft.js Weekly 3/24/17\n\n* Upcoming 0.10.1 release\n    * Last blocker is figuring out Entity deletion change - debugging issues with https://github.com/facebook/draft-js/pull/1065\n"
  },
  {
    "path": "meta/meeting-notes/2017-03-31-weekly-meeting.md",
    "content": "# Draft.js Weekly 3/31/17\n\n* Introduced Feature Flags\n* Releasing from Master, instead of a release branch\n    * Ideally this will speed up release process\n* Discussion of how to automate syncing of Facebook changes to Draft to Github, and Github changes of Draft to Facebook.\n"
  },
  {
    "path": "meta/meeting-notes/2017-04-14-weekly-meeting.md",
    "content": "# Draft.js Weekly 4/14/17\n\n* Continued discussion of automated syncing between Facebook and Github versions of Draft, to speed up release process\n* How to enable external folks to help maintain Draft?\n* Discussion of finding more Facebook maintainers\n"
  },
  {
    "path": "meta/meeting-notes/2017-04-21-weekly-meeting.md",
    "content": "# Draft.js Weekly 4/21/17\n\n* Discussed fixes for bugs\n* [Gboard auto-translate](https://www.theverge.com/2017/3/9/14864048/google-gboard-keyboard-android-google-translate)\n  * maybe look into how this affects Draft\n          * also look at if/when this would be on Android\n\n\n"
  },
  {
    "path": "meta/meeting-notes/2017-04-28-weekly-meeting.md",
    "content": "# Draft.js Weekly 4/28/17\n\n* still working on internal sync of v0.10.1\n"
  },
  {
    "path": "meta/meeting-notes/2017-05-05-weekly-meeting.md",
    "content": "# Draft.js Weekly 5/05/17\n\n* Internal testing of v0.10.1 going well\n* Some folks out at JSConf EU\n"
  },
  {
    "path": "meta/meeting-notes/2017-05-19-weekly-meeting.md",
    "content": "# Draft.js Weekly 5/19/17\n\n* Draft v0.10.1 release went smoothly\n"
  },
  {
    "path": "meta/meeting-notes/2017-05-26-weekly-meeting.md",
    "content": "# Draft.js Weekly 5/26/17\n\n* Planning a bug-bash/issues triage session in June\n* Posting internally at FB to recruit more maintainers\n"
  },
  {
    "path": "meta/meeting-notes/2017-06-02-weekly-meeting.md",
    "content": "# Draft.js Weekly 6/02/17\n\n* Discussed ongoing fix to work better with React Fiber\n* Set date for internal FB bug/issues bash in mid June\n* Onboarding new internal maintainers\n"
  },
  {
    "path": "meta/meeting-notes/2017-07-07-weekly-meeting.md",
    "content": "# Draft.js Weekly 07/07/17\n\nAgenda Items:\n\n* Goal: Review/close 30 PRs by end of the half.\n    * Review 3 every Friday\n    * Close or import at least 2 by Monday\n    * If no problems are caused by following Friday, include in a minor release or patch.\n* Update on automated PR syncing between Github and Facebook\n  * Almost finished setting this up\n* Onboarding new internal maintainers\n* New logging of internal use of Draft - it's widely used :)\n\nPRs to consider:\n\n* 1190 (https://github.com/facebook/draft-js/pull/1190) - selection.extend is called on selection without ranges\n    * Commented with requirements to merge, following up in a week\n    * “Selection code is the scariest part of this whole codebase, I think... This doesn't even surprise me that this bug exists.” - Isaac\n    * Might close https://github.com/facebook/draft-js/pull/1203 in favor of #1190 but it's in IE11, so we are following up with our contacts at MS\n* (for next week) 1170 (https://github.com/facebook/draft-js/pull/1170) - updates syntax in docs, just need to get CI passing. Not sure why it failed.\n* (for next week) 927 (https://github.com/facebook/draft-js/pull/927) - don't merge sequential unstyled tags\n\n\n\n\n"
  },
  {
    "path": "meta/meeting-notes/2017-07-14-weekly-meeting.md",
    "content": "# Draft.js Weekly 07/14/17\n\nAgenda Items:\n\n* Intros for new folks\n* Update on automated PR syncing between Github and Facebook\n  * Working as of today!\n* Bug fixes - fix typing into text node containing tab\n  * Merged on Github as https://github.com/facebook/draft-js/commit/5863399a3a1bcbbe9b090249504a70496a7af7cc\n\nPRs to consider:\n\n* 1285 (https://github.com/facebook/draft-js/pull/1285) - 'Added support for the `compositionUpdate` event'\n    * This is only for Android, but we don't want to browser sniff if we can help it\n    * Also events vary by keyboard so we can't sniff for that\n    * Concern: composition events are different in each browser/OS combination, and we want to avoid breaking them\n    * At very least we would want to manually test across different browsers/OS, with IME and different languages\n    * If it falls back to 'compositionUpdate' instead of falling back to 'beforeInput' that is a smaller change\n    * Another complication; the 'beforeInput' event is “normalized” in React.\n        * Another potential fix; change the 'beforeInput' in React to fire based on 'compositionUpdate'.\n        * Might eventually pull this code from React into Draft\n    * Would merge if:\n        * we manually test across OS/browsers\n        * fall back to 'compositionUpdate'\n        * test internally on FB employees for a week or so\n* (for next week) 927 (https://github.com/facebook/draft-js/pull/927) - don't merge sequential unstyled tags\n* (for next week) 1170 (https://github.com/facebook/draft-js/pull/1170) - updates syntax in docs, just need to get CI passing. Not sure why it failed.\n    * Will follow up soon\n* (from last week)\n    * 1190 (https://github.com/facebook/draft-js/pull/1190) - selection.extend is called on selection without ranges\n        * No response to comments last week\n        * Pinged the PR and issue again to see if anyone is interested in debugging Chrome issue\n\n\n\n\n"
  },
  {
    "path": "meta/meeting-notes/2017-07-21-weekly-meeting.md",
    "content": "# Draft.js Weekly 07/21/17\n\nAgenda Items:\n\n* Intros\n* Minor release soon? We have a couple of bug fixes and the 'ariaMultiline' prop.\n* look at PRs\n* 'good first bug' issues for new folks?\n\nPRs to consider:\n\n* 1170 (https://github.com/facebook/draft-js/pull/1170) - updates syntax in docs, just need to get CI passing. Not sure why it failed.\n    * Why is CI failing here?\n      * @spicyj figured it out - Might need to revert to a version of React before flat bundles\n      * Could open an issue to fix website so that it works with flat bundles\n* Next steps for ungating fix for https://github.com/facebook/draft-js/issues/1020#issuecomment-316620738\n    * https://github.com/facebook/draft-js/blob/master/src/component/handlers/edit/editOnFocus.js#L37-L39\n    * Chrome version should be out within next month: https://www.chromium.org/developers/calendar\n* (from last week)\n    * PRs close to merging but need a bit more, ongoing dialog:\n        * 1190 (https://github.com/facebook/draft-js/pull/1190) - selection.extend is called on selection without ranges\n            * Should we bump priority of this?\n            * https://our.intern.facebook.com/intern/tasks/?t=18541443\n            * opened internal task for following up on this\n        * 1285 (https://github.com/facebook/draft-js/pull/1285) - 'Added support for the `compositionUpdate` event'\n            * @flarnie is going to follow up on this\n\nAction Items:\n\n* Fix up and merge this: https://github.com/facebook/draft-js/pull/1285 (flarnie, tagging Chang + Draft_js for review)\n* also fix up and merge this: https://github.com/facebook/draft-js/pull/1170\n* Find and share some good-first-bugs and share with new maintainers (@flarnie)\n* Next week look at open issues (all maintainers)\n"
  },
  {
    "path": "meta/meeting-notes/2017-07-28-weekly-meeting.md",
    "content": "# Draft.js Weekly 07/28/17\n\nAgenda Items:\n\n* Intros\n* v0.11.0 alpha release 🎉 - https://github.com/facebook/draft-js/issues/1312\n* Updates/questions on 'good first bug' tasks for new maintainers\n* Look at *issues (not PRS this week)*\n"
  },
  {
    "path": "meta/meeting-notes/2017-08-04-weekly-meeting.md",
    "content": "# Draft.js Weekly 08/04/2017\n\nAgenda Items:\n\n* Intros\n* Anyone want to do one of these two tasks?\n    *  “**[Draft.js] Update DraftEntity syntax in stateToMarkdown.js and stateFromMarkdown.js”** (internal task t15467849)\n    * “**[Draft.js] File bug with Chrome for failure of `selection.addRange`**” (internal task t20310053)\n    * If not @flarnie will delegate or do it myself this week.\n* Continue Issue triage\n\n"
  },
  {
    "path": "meta/meeting-notes/2017-08-11-weekly-meeting.md",
    "content": "# Draft.js Weekly 08/11/2017\n\nAgenda Items:\n\n* Intros\n* React team maintainers mainly working on React 16.0 release\n* project being planned to bring more internal maintainers onto Draft.js for a\n  1-month project\n* Continue Issue triage\n    * Closed some issues\n    * Hoping to find second opinion on https://github.com/facebook/draft-js/issues/1334 but probably could accept proposed fix\n\nAction Items:\n* Making plan for continued work on releasing v0.11.0 and fixing open bugs\n"
  },
  {
    "path": "meta/meeting-notes/2017-08-18-weekly-meeting.md",
    "content": "# Draft.js Weekly 08/18/2017\n\nDraft.js Weekly 08/18/201\n\nAgenda Items:\n* Intros\n* React team maintainers mainly working on React 16.0 release (again)\n* Upcoming stuff:\n    * Month-long Draft.js improvement project in the works (still)\n    * Issues bash being planned\n* Continue Issue triage\n"
  },
  {
    "path": "meta/meeting-notes/2017-09-01-weekly-meeting.md",
    "content": "# Draft.js Weekly 09/01/2017\n\nAgenda Items:\n* Intros\n* Upcoming stuff:\n    * WIP - Hack-a-month to support richer features in Draft.js (internal only please)\n        * Big refactors are scary - how to approach this?\n            * Taking lessons from React; incremental upgrade path\n            * React had a good test suite; when you fix a bug, add a test\n                * With Draft some parts are almost impossible to test\n                * Put things behind a feature flag initially\n                * Similar to getting Draft into comments\n                    * Did many experiments, took forever\n                    * bifurcate and some people get new, some people get old\n                    * obsessively look through flytrap\n                    * when things broke, people reported it\n                    * eventually it was not breaking so badly, could ship it\n                    * DOM Selection state is hard to test\n            * Every feature we add would have a test\n            * QA contractors\n            *\n\n* Gaps in flow coverage could be good-first-bug issues\n\nAction Items:\n* Make some good-first-bug issues\n    *  for flow coverage\n    * and unit tests\n    * should we have a flow-typed directory\n"
  },
  {
    "path": "meta/meeting-notes/2017-09-08-weekly-meeting.md",
    "content": "# Draft.js Weekly 09/08/2017\n\nAgenda Items:\n* * Super awesome docs PR - https://github.com/facebook/draft-js/pull/1371#pullrequestreview-61521213\n* How does long-term OS work at FB?\n    * Projects to take inspiration from\n        * React\n            * has a team building new things in the open\n            * this is the far side of the spectrum\n        * FB has had other projects which were put in OS and then dropped fully\n        * Draft is in the middle\n            * Some level of ownership (weekly meetings, part-time maintainers)\n    * General impression\n        * Encouraged but not fully supported, could be better supported\n        * Generally FB wants external folks to take over, unless it is a big enough project for a whole team\n        * Hard for people to know how much to value it in calibrations\n        * Hard to know the impact of work for community vs. internal focused work\n        * The OS team is working on figuring this out\n    * For new projects\n        * New OS projects require eng. director sign off, team commits to support for 6 months\n        * But what happens after the 6 months pass?\n    * What about external maintainers?\n        * React example:\n            * External folks are very involved, very helpful, especially for non-critical things\n            * Can't actually offload that much work onto them;\n                * Often requires context on big picture or internal changes\n            * Plus we worry about them landing big changes without seeing the effects within FB\n        * Even more is up in the air -\n            * They might have different priorities, unknown commitment\n    * Draft basically “works” for most use cases, is in a pretty good state\n        * Community needs and FB needs are basically the same, if someone worked on it full time internally it would likely hit community needs 100%\n        * It's a narrow project - lends itself to stability\n        * Could make a case for more investment within FB potentially\n\n\n\n\n"
  },
  {
    "path": "meta/meeting-notes/2017-09-15-weekly-meeting.md",
    "content": "# Draft.js Weekly 09/15/17\n\n* Proposal to support multiple entities per character - https://github (https://github.com/facebook/draft-js/pull/1315).com/facebook/draft-js/pull/1315 (https://github.com/facebook/draft-js/pull/1315)\n  * Agreed that we aren't ready to merge this, need more time to consider, not sure when we would be\n"
  },
  {
    "path": "meta/meeting-notes/2017-09-22-weekly-meeting.md",
    "content": "# Draft.js Weekly 09/22/17\n\n* Better test coverage for Draft and browser changes\n    * Interesting issue: “`focus()` cause unexpected scroll” on Chrome 61 only (https://github.com/facebook/draft-js/issues/1381)\n    * How to catch/prevent this next time?\n    * Only mention of this breaking change is one bullet at very end of Chrome 61 blog post: https://blog.chromium.org/2017/08/chrome-61-beta-javascript-modules.html\n    * Maybe integration/webdriver tests on Chrome Canary, Firefox Nightly, etc.\n    * See if current webdriver tests cover it\n    * Also look into external services, esp. for mobile\n\n* Update: Entities, RTL still somewhat broken in Android\n"
  },
  {
    "path": "meta/meeting-notes/2017-09-29-weekly-meeting.md",
    "content": "# Draft.js Weekly 09/29/17\n\n* Issues with landing PRs into FB - instructions for landing a PR written up\n  internally\n* Goal: Close or merge the 10 oldest PRs\n    * Most interesting one so far: “Expose (most) transactions” - https://github.com/facebook/draft-js/pull/265\n\n\n\n\n"
  },
  {
    "path": "meta/meeting-notes/2017-10-06-weekly-meeting.md",
    "content": "# Draft.js Weekly 10/06/17\n\n* Discussed race conditions in Draft.js\n"
  },
  {
    "path": "meta/meeting-notes/2017-10-13-weekly-meeting.md",
    "content": "# Draft.js Weekly 10/13/17\n\n* * Idea: Highlight broken/invalid text in red (Sophie's comments below:)\n    * bad things happen when we get text in a DraftEditorLeaf span that's outside the innermost one\n    * in particular, when text content is a sibling of the inner span here, it looks like it's real text but draft doesn't handle it properly\n    * idea: CSS to make it bright red\n    * so that people are more likely to notice if certain keyboard shortcuts, for example, cause the text to get out of sync with draft\n    * they'll complain \"hey, whenever I do this really weird thing, I get red text\" and then we'll have a good avenue to say \"…well yeah. don't do that. also maybe we'll fix it\"\n    * -> Maybe try this for one FB use case first and see how it goes? Or land under a GK and enable within FB?\n\n\n* One World for continuous testing\n    * Notes on setting this up within FB\n    * Might be useful as regression tests\n        * Could still add regression tests that don't use live browser\n    * What about for React?\n        * Dan and Nate and Brendan are looking at this with 3rd party extensions, like Saucelabs\n            * Problem; some of our fixtures are hard to write automated test for. Some bugs in the past related to setting the value correctly, but looking visually it wasn't showing up. Hard to catch this with automated test.\n* Consider adding Jest tests for PRs that pass tests but would break everything\n* Tests are awesome. :| Let's add more. :D\n"
  },
  {
    "path": "meta/meeting-notes/2017-10-20-weekly-meeting.md",
    "content": "# Draft.js Weekly 10/20/17\n\n* Potentially onboarding external maintainers\n* Upcoming project to add new improved features to Draft.js, within FB\n* Bug Bash planning\n"
  },
  {
    "path": "meta/meeting-notes/2017-11-03-weekly-meeting.md",
    "content": "# Draft.js Weekly 11/03/17\n\n* Update on new experimental feature\n* Migrating docs to Docusaurus - https://docusaurus.io/\n* Tests being rewritten with Jest snapshots\n"
  },
  {
    "path": "meta/meeting-notes/2017-11-17-weekly-meeting.md",
    "content": "# Draft.js Weekly 11/17/17\n\n* Continued work moving docs to Docusaurus\n* Jest snapshot test conversion landed\n* New maintainers\n"
  },
  {
    "path": "meta/meeting-notes/2017-12-01-weekly-meeting.md",
    "content": "# Draft.js Weekly 12/01/17\n\n* Moving weekly meeting time so more folks can attend\n* Update on Docusaurus migration\n"
  },
  {
    "path": "meta/meeting-notes/2017-12-08-weekly-meeting.md",
    "content": "# Draft.js Weekly 12/08/17\n\n* Review ongoing work on experimental feature\n* Need to fix CI\n"
  },
  {
    "path": "meta/meeting-notes/2017-12-15-weekly-meeting.md",
    "content": "# Draft.js Weekly 12/15/17\n\n* Discussed issues which arise when using Draft.js with React's \"async\n  scheduling\" enabled.\n"
  },
  {
    "path": "meta/meeting-notes/2018-01-05-weekly-meeting.md",
    "content": "# Draft.js Weekly 01/05/18\n\n* Docusaurus migration almost complete, thanks @aadsm\n* Update on experimental features\n  * Planning on rolling out and testing within FB first, no plans to release to\n    open source for at least next 6 months.\n\n* Demo of debugger/playground tool - thanks @mitermayer & @juliankrispel\n* 0.11.0 update?\n  * Nobody is working on it, not sure when we will finish roll out\n"
  },
  {
    "path": "meta/meeting-notes/2018-01-19-weekly-meeting.md",
    "content": "# Draft.js Weekly 01/19/18\n\n* Tried to fix CI, linting inconsistencies\n"
  },
  {
    "path": "meta/meeting-notes/2018-01-26-weekly-meeting.md",
    "content": "# Draft.js Weekly 01/26/18\n\n* Switching to biweekly for a while\n* Discussed support for upcoming API changes in React in Draft.js\n* No updates on experimental new features\n* Docusaurus docs migration\n  * Planning on looking into Netlify\n  * Might land change before deciding about Netlify\n* Why don't we support mobile web, and how to tell the community this\n  * Really it's just Android we don't support\n  * android behaves very differently from most desktop browsers\n  * iOS behaves mostly like a desktop browser\n  * write one really good response and link to that\n* Discussed internal PR to expose start/end of positions of decorated\n  component within a contentBlock (D6712533)\n  * lgtm!\n* Discussed more potential new maintainers\n* How to fix/import PRs which don't give maintainers permission to\n  push to them?\n* There is still a bug with selecting and typing the same character;\n  * Flarnie will look at this again\n\n"
  },
  {
    "path": "meta/meeting-notes/2018-02-08-weekly-meeting.md",
    "content": "# Draft.js Weekly 02/08/18\n\n* Intros - welcome to Twitter web team! 🎉\n* Discussion:\n    * Twitter team planning to try Draft.js for their Web UIs\n        * We can commit to regularly merge their PRs\n        * TODO: get a list of their github handles, to respond to their PRs in particular.\n        * Their discussion items:\n            * They will use it on mobile\n            * It will take a while to go public, they will focus on quality\n            * Asking about test coverage\n                * We need more :)\n            * What will the flow be?\n                * internal PR and review\n                * Should they write a feature flag into their code\n                * TODO: send them a link to the file with feature flags changes recently\n            * Mobile bugs\n                * using default android keyboard and pressing space\n                * MS swift keyboard\n                * other major issues?\n                    * Sophie - Right now Draft.js keeps state of DOM and editor in sync\n                        * it does this by listening to each event, then updating internal state\n                        * in some cases Draft.js will call event.preventDefault on event, and in others we allow native event to happen\n                            * Doesn't happen much but we try to allow it when we can. Spellcheck is an example.\n                        * the issue is on Android, they don't send input events for a lot of the things that you would want them for. They only send a single input event, not keypress, not beforeInput, etc. and input event doesn't have keycode. Only way to figure out what happened is look at DOM and diff, figure out what changed.\n                        * So far we have not implemented anything like that, because all other browsers do sent useful events and it's a big refactor.\n                        * It would be possible, but a substantial amount of work. Needs to be done to support Android.\n                        * Seems to be a challenge of contenteditable on any framework.\n                    * Twitter lead -\n                        * They want to go in this direction, happy we are supportive.\n                    * Sophie\n                        * She can talk more about how this could work.\n                    * Twitter lead -\n                        * Where does FB fallback to textarea?\n                    * Sophie\n                        * Depends. Recently decided to exclude iOS and using Chinese/Japanese bc of IME bugs in iOS.\n                        * Depends on your users and features. Doesn't matter that much for that case.\n                    * Twitter lead -\n                        * Problems with some languages - on desktop or mobile web? Facebook only uses it on desktop right?\n                    * Sophie\n                        * Generally right, only desktop.\n                    * Twitter lead -\n                        * Do you think it's a big problem with IME?\n                    * Sophie\n                        * We do have some problems with IME in IE, up to IE 11 but Edge is ok.\n                        * That's similar to what happens on android, where it doesn't send the events we need.\n                        * Right now we exclude cjk languages from getting Draft input on IE. IE is a small fraction for us.\n                    * Twitter lead -\n                        * Long term tehy would like to see Draft.js be configurable, in terms of decreasing the bundle size. It's a hard thing to do.\n                        * One concern is the size.\n                    * Alan\n                        * Do you have specific goals, how small would it be if it wasn't a problem?\n                    * Twitter lead -\n                        * 70k is a little big\n                        * They don't use immutable-js, they don't care about “large error maps”\n                        * old compose bundle was ~30k gzipped\n                        * importing draft.js increases to ~90kb\n                    * Flarnie\n                        * More details on the approach proposed?\n                    * Sophie\n                        * Could do everything that way\n                    * More about how we can do this?\n                        * Could do it incrementally - Twitter team has done similar things with their previous editor\n                        * Do we rewrite or incrementally\n                    * How to work through this?\n                        * Sophie - start with a meeting to walk through how it works, Sophie can give that\n                        * We will follow up via email about the\n\n*Action Items:*\n\n* Put out internal task to refactor https://github.com/facebook/draft-js/blob/master/src/model/encoding/convertFromHTMLToContentBlocks.js (Flarnie)\n* Get list of Twitter team github handles (Flarnie)\n* Set up meeting with Twitter folks to explain Draft architecture (Sophie)\n* Email about next steps (Sophie and/or Flarnie)\n\n\n\n"
  },
  {
    "path": "meta/meeting-notes/2018-02-23-weekly-meeting.md",
    "content": "# Draft.js Weekly 02/08/18\n\n* DELAYED until next week: Demo of new filesize tracking courtesy of  Alan Norbauer\n    * in https://github.com/facebook/draft-js/pull/1644\n\n* Update from Twitter team\n    * Working on integrating Draft into their composer, no changes yet\n    * They have a prototype on mobile, iOS is ok except for autocorrect\n    * on Android there are some keyboards that don't accept any input from users. Major issues needing fixed.\n* Looking into Chrome 65 issue, where mouse movement triggers composition events\n    * https://github.com/facebook/draft-js/issues/1657\n* Update coming next time about tree block data structure support\n* Isaac and Sophie discussing mobile support\n    * Sophie: preventing/controlling events seems to not work on android\n    * Isaac: yea, that might be the direction to go in, since android and now Chrome don't have consistent event systems\n    * Overall consensus - if Twitter folks can put in effort, we support rearchiteture of Draft.js to better support mobile web.\n"
  },
  {
    "path": "meta/meeting-notes/2018-09-07-meeting.md",
    "content": "# Draft.js Meeting Notes - 9/7\n## Attendees\n- Claudio (Facebook, data center tools team in Dublin)\n- Flarnie (Facebook, long-time maintainer who is transitioning away)\n- Julian (Maintainer of https://github.com/draft-js-plugins)\n- Marco (Facebook, Workplace team in London)\n- Nivedita (Facebook, Internal Tools team)\n- Yuze (Twitter, leading the Draft.js integration for Twitter)\n\n## Project Updates\n**Tree Data implementation** (Nivedita)\n\n- The current block list model is ill-suited for tables, layouts \\& other complex behaviours.\n- Tables are important for some FB-internal tools \\& tree data is the best way to implement these.\n- Bulk of this work was implemented by Mitermayer \\& Flarnie; Nivedita is currently implementing a few missing pieces \\& getting it ready to test on FB internal tools.\n- No plans at the moment to migrate other FB usages to the tree data model and/or deprecate the current data model.\n\n**Twitter** (Yuze)  \n\n- They have forked Draft and made some incremental changes.\n- React \\& Draft are being used in the new version of the website.\n- They are planning to contribute some issues \\& PRs back to Draft related to their work.\n- They had earlier planned to work on making mobile support more resilient but it is not currently on their near-term roadmap.\n\n## Discussion\n**What are the biggest pain points around working with Draft.js today?**\n\nThe main issue is that it is hard to contribute (get your PR addressed/issue fixed) \\& lack of response / timeliness makes potential contributors reluctant to submit PRs.  \n\n- There is no clear guidance on what it would take for a PR to get reviewed \\& accepted.\n- The two pain points from the FB maintainer side have been:\n    - Lack of resources (this is still a side project for everyone rather than a team owning Draft.js, but hopefully with more maintainers now we can contribute a few hours every week between us).\n    - Needing to ensure (via a manual process) that external PRs don't break Facebook, which is why we have been very conservative.\n- What can help?\n    - Clear guidelines on what PRs need to have to get accepted.\n    - Better suite of test cases - possibly we can get help from the OS community on this.\n    - If possible, a way to expose some way to run part or all of the FB test suite.\n    - Codify part or all of the manual test process if possible.\n- Action Items (potentially over the next month):\n    - Explore some of the existing PRs to evaluate whether or not they can be pulled in.\n    - Come up with some better guidelines for PRs \\& communicate these to the community.\n    - Figure out what test cases are missing \\& seek out the community's help in adding these to the project.\n\n**Brainstorm of ways in which we can deal with existing issues \\& PRs**  \n\n- Bug bash\n- Take a pass at adding tags \\& labels for issues (such as \\`good first issue\\`).\n- Create a more active community, which is more involved in fixing issues. Conferences / events / meetups.\n\n**Release process** \n \n- Flarnie used to do regular releases every few weeks or months, but didn't have as much time over the past few months.\n- We wanted to cut 0.11 but there were some breaking changes - getting this shipped is low-pri.\n- We could remove the two-way sync into Facebook master to let the open source community contribute without as much friction.\n- But it will be really hard to get these back in sync / pull changes in.\n- Yuze gains confidence to pull in latest commits into their fork because Facebook is using this continuously.\n- We agreed that forking is a bad idea.\n  \nNext meeting will be in two weeks.  \n"
  },
  {
    "path": "meta/meeting-notes/2018-10-12-meeting.md",
    "content": "# Draft.js Meeting Notes - 10/12\n\n## Attendees\nClaudio Procida, Flarnie Marchan, Julian Krispel, Marco Botto, Nivedita Chopra, Philip Chmalts (Chegg), Sophie Alpert.\n\n## Updates\n\n**Tree Data (Nivedita)**\n\n* Currently being dogfooded internally.\n* Majority of the functionality is built, currently finding and fixing many small bugs.\n* Planning to write docs soon.\n* Phil's use case in Chegg is for nested entities, which nested blocks can help with.\n\n## Discussion\n\n**What are the blockers for cutting a new release?**\n\n* Bundle size has increased by 35% from 526.3 kb to 711.3 kb (more details below).\n* (not really a blocker) Tests are still insufficient and do not provide much coverage.\n\n**Bundle Size**\n\n* We currently have a script that generates bundle size stats. The idea is that this script can help (someone) look at each commit and each bundle and figure out where the most size was introduced.\n* It only runs on `yarn build` and so is included in some PRs and not others, causing some confusion amongst contributors. Flarnie has opened #1900 as follow-up for better documentation here.\n* Bundle size has increased by 200k. Top 3 causes of size increase from the previous release are:\n  * duplicate copy of the html converstion utility, we need to remove one.\n  * the tree-data migration in-progress\n  * the entity storage migration in-progress\n\n(thanks to Flarnie for pulling these stats and providing the historical context)\n\n**Will splitting `immutable` as a peer dependency help with bundle size?**\n\n* `npm` should automatically hoist dependencies so this shouldn't matter for size purposes.\n* Moving `immutable` to a peer dependency will add friction to using Draft.js out of the box, so it's a bad idea.\n\n**Guidelines for merging PRs**\n\n* Can we expose internal tests? No. There is also only one sanity check webdriver test & a few product tests that we have never seen fail.\n* For now, we're still prioritizing low-risk PRs for bugs, tests & docs.\n* Nivedita has been importing to Phabricator to run the internal test suite, doing a manual sanity check on FB composer & Intern Editor, and staggering each land by a few hours (during Menlo Park business hours only) to make it easier to bisect & revert in case of breakage.\n* If we publish a roadmap, it will help guide the community on which PRs are higher priority for us.\n\n## Roadmap - Initial Brainstorm\n* Publish a new release\n  * Not publishing `v0.11.0` yet ([which contains API-breaking changes](https://github.com/facebook/draft-js/issues/839)). \n  * This will be `v0.10.6` since `v0.10.5` was published in January.\n  * Need to reduce bundle size (being led by Flarnie & Claudio, with community help).\n  * Will also need documentation updates & comms around the new release (Julian is leading this).\n  * (potential) Introduce semantic versioning for commits ([e.g. in React](https://reactjs.org/docs/how-to-contribute.html#semantic-versioning)) that will help with pulling release notes more easily (Marco may help with this).\n* Tree Data\n  * Goal is to cut a release (potentially `v0.10.7`) with stable Tree Data ready for opt-in use.\n  * Aim to have docs ready in the next two weeks (action item for Nivedita). This will give more context to potential dogfooders & contributors.\n  * Expose pending bugs, issues & release blockers on GitHub so the community can help with this (Julian & Flarnie are interested in this, as well as a couple of other folks at FB).\n  * Provide an example with tables implementation based on tree data (Nivedita will be building this initially for an internal use case & then exposing externally in Draft.js `examples` directory).\n* Community\n  * Guidelines for issue triage via tags (#1896).\n  * Guidelines for PRs to be merged (#1897).\n  * Publish roadmap for transparency (#1898).\n  * Continue to publish meeting notes.\n\nNext meeting in two weeks - we are now setting up a biweekly meeting series. The community can flag any issues that they would like to be addressed in our meetings by adding the `meeting agenda` tag."
  },
  {
    "path": "meta/roadmaps/2017-h1.md",
    "content": "# H1 2017 Roadmap Update\n\n**tldr:** Our first goal is to achieve stability by catching up on releases, bug fixes, issues, and PRs. Other work on Draft.js is helpful, but may not get prioritized until the project reaches stability goals.\n\n**Goal: project stability**\n\n* Stable, regular releases\n* Issues are triaged and closed regularly\n* PRs are responded to and closed regularly\n\n**The Master Plan:**\n\n**Phase 1:** 🔥 Fix\n\n**Phase 2:** 🔧  Refactor\n\n**Phase 3:** 💅  Polish\n\nMore on each phase below;\n\n## Phase 1: Fixing the Problems\n\n### January - June 2017 Roadmap\n\n(NOTE: Imagine this as a timeline rather than an ordered list.)\n\n1. ~~Release 0.10.0~~ [v0.10.0 released](https://github.com/facebook/draft-js/releases/tag/v0.10.0)\n\n2. Release 0.11.0@next for beta testing by community\n\n3. Release any interim bug fixes as 0.10.1\n\n4. Release 0.11.0, fully deprecating DraftEntity module\n\n5. Start bi-weekly release cycle\n\n6. Increased focus on reducing open PR and issue count\n\n\n## Phase 2: Refactoring and Exploring\n\nAfter establishing a stable state for the Draft.js project, we look forward to exploring new features and approaches. Some possible examples:\n\n* Mobile browser support\n* Nested blocks and nested decorators, possibly using a tree block structure (https://github.com/facebook/draft-js/issues/143). This would be following up on the work started by SamyPesse and Mitermayer in https://github.com/facebook/draft-js/pull/388\n* Exploring collaborative editing as a possible feature\n* Improving copy/paste behavior\n\n## Phase 3: Improve All the Things\n\nOnce we finish any significant refactors it's a safe time to focus on documentation, testing, and overall improvement of the codebase. Some possible examples:\n\n* Increasing test coverage\n* Improving documentation and writing tutorials\n* Adding increased linting and modernizing the codebase with codemods\n\nThis could be when we consider a 1.0 release, if not sooner.\n\nThanks to the community for all your support and feedback - we look forward to\ncontinuing to improve Draft.js.\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"draft-js\",\n  \"description\": \"A React framework for building text editors.\",\n  \"version\": \"0.11.7\",\n  \"keywords\": [\n    \"draftjs\",\n    \"editor\",\n    \"react\",\n    \"richtext\"\n  ],\n  \"homepage\": \"http://draftjs.org/\",\n  \"bugs\": \"https://github.com/facebook/draft-js/issues\",\n  \"files\": [\n    \"dist/\",\n    \"lib/\",\n    \"LICENSE\"\n  ],\n  \"main\": \"lib/Draft.js\",\n  \"style\": \"dist/Draft.css\",\n  \"repository\": \"facebook/draft-js\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"prepublish\": \"npm run build\",\n    \"pretest\": \"node node_modules/fbjs-scripts/node/check-dev-engines.js package.json\",\n    \"build\": \"gulp\",\n    \"dev\": \"gulp dev\",\n    \"postbuild\": \"node node_modules/fbjs-scripts/node/check-lib-requires.js lib\",\n    \"lint\": \"eslint .\",\n    \"lint-docs\": \"alex . && yarn format-docs:diff\",\n    \"format\": \"eslint . --fix\",\n    \"format-docs\": \"prettier --config prettier.config.js --write \\\"docs/**/*.md\\\"\",\n    \"format-docs:diff\": \"prettier --config prettier.config.js --list-different \\\"docs/**/*.md\\\"\",\n    \"flow\": \"flow src\",\n    \"test\": \"cross-env NODE_ENV=test jest\",\n    \"test-ci\": \"cross-env NODE_ENV=test npm run lint && npm run flow && npm run test\"\n  },\n  \"dependencies\": {\n    \"fbjs\": \"^3.0.4\",\n    \"immutable\": \"~3.7.4\",\n    \"object-assign\": \"^4.1.1\"\n  },\n  \"peerDependencies\": {\n    \"react\": \">=0.14.0\",\n    \"react-dom\": \">=0.14.0\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.11.6\",\n    \"@babel/plugin-proposal-nullish-coalescing-operator\": \"^7.10.4\",\n    \"@babel/plugin-proposal-optional-catch-binding\": \"^7.10.4\",\n    \"@babel/plugin-proposal-optional-chaining\": \"^7.11.0\",\n    \"alex\": \"^9.0.1\",\n    \"babel-eslint\": \"^10.1.0\",\n    \"babel-preset-fbjs\": \"^3.3.0\",\n    \"cross-env\": \"^7.0.2\",\n    \"del\": \"^5.1.0\",\n    \"es6-shim\": \"^0.35.5\",\n    \"eslint\": \"^7.8.1\",\n    \"eslint-config-fbjs\": \"^3.1.1\",\n    \"eslint-config-prettier\": \"^6.11.0\",\n    \"eslint-plugin-babel\": \"^5.3.1\",\n    \"eslint-plugin-fb-www\": \"^1.0.3\",\n    \"eslint-plugin-flowtype\": \"^5.2.0\",\n    \"eslint-plugin-jsx-a11y\": \"^6.3.1\",\n    \"eslint-plugin-prettier\": \"^3.1.4\",\n    \"eslint-plugin-react\": \"^7.20.6\",\n    \"fbjs-scripts\": \"^2.0.0\",\n    \"flow-bin\": \"^0.130.0\",\n    \"gulp\": \"^4.0.2\",\n    \"gulp-babel\": \"^8.0.0\",\n    \"gulp-clean-css\": \"^4.3.0\",\n    \"gulp-concat-css\": \"^3.1.0\",\n    \"gulp-derequire\": \"^3.0.0\",\n    \"gulp-flatten\": \"^0.4.0\",\n    \"gulp-header\": \"^2.0.9\",\n    \"gulp-if\": \"^3.0.0\",\n    \"gulp-rename\": \"^2.0.0\",\n    \"gulp-util\": \"^3.0.8\",\n    \"jest\": \"^26.4.2\",\n    \"prettier\": \"1.19.1\",\n    \"react\": \"^16.8.0\",\n    \"react-dom\": \"^16.8.0\",\n    \"react-test-renderer\": \"^16.0.0\",\n    \"stats-webpack-plugin\": \"^0.7.0\",\n    \"through2\": \"^4.0.2\",\n    \"uglifyjs-webpack-plugin\": \"^2.2.0\",\n    \"webpack-stream\": \"6.1.0\"\n  },\n  \"devEngines\": {\n    \"node\": \"14.x || 16.x\",\n    \"npm\": \"2.x || 3.x || 5.x || 6.x || 7.x || 8.x\"\n  },\n  \"jest\": {\n    \"globals\": {\n      \"__DEV__\": true\n    },\n    \"rootDir\": \"./\",\n    \"roots\": [\n      \"<rootDir>/src/\"\n    ],\n    \"setupFiles\": [\n      \"<rootDir>/scripts/jest/shims.js\"\n    ],\n    \"transform\": {\n      \".*\": \"<rootDir>/scripts/jest/preprocessor.js\"\n    },\n    \"haste\": {\n      \"hasteImplModulePath\": \"<rootDir>/scripts/jest/hasteImpl.js\"\n    },\n    \"modulePathIgnorePatterns\": [\n      \"<rootDir>/lib/\",\n      \"<rootDir>/node_modules/\"\n    ],\n    \"transformIgnorePatterns\": [\n      \"<rootDir>/node_modules/\"\n    ],\n    \"unmockedModulePathPatterns\": [\n      \"<rootDir>/node_modules/fbjs/node_modules/\",\n      \"<rootDir>/node_modules/fbjs/lib/UserAgent.js\",\n      \"<rootDir>/node_modules/fbjs/lib/UserAgentData.js\",\n      \"<rootDir>/node_modules/fbjs-scripts/\",\n      \"<rootDir>/node_modules/immutable/\",\n      \"<rootDir>/node_modules/object-assign/\",\n      \"<rootDir>/node_modules/react/\",\n      \"<rootDir>/node_modules/react-dom/\"\n    ]\n  }\n}\n"
  },
  {
    "path": "prettier.config.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nmodule.exports = {\n  singleQuote: true,\n  trailingComma: 'all',\n  bracketSpacing: false,\n  jsxBracketSameLine: true,\n  overrides: [\n    {\n      files: '*.js',\n      options: {\n        parser: 'flow',\n      },\n    },\n    {\n      files: '*.md',\n      options: {\n        printWidth: 80,\n      },\n    },\n  ],\n};\n"
  },
  {
    "path": "scripts/jest/hasteImpl.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\n\n'use strict';\n\nconst path = require('path');\n\nconst ROOT = path.join(__dirname, '..', '..');\n\nconst BLACKLISTED_PATTERNS/*: Array<RegExp>*/ = [\n  /.*\\/__(mocks|tests)__\\/.*/,\n];\n\nconst WHITELISTED_PREFIXES/*: Array<string>*/ = [\n  'src'\n];\n\nconst NAME_REDUCERS/*: Array<[RegExp, string]>*/ = [\n  // extract basename\n  [/^(?:.*\\/)?([a-zA-Z0-9$_.-]+)$/, '$1'],\n  // strip .js/.js.flow suffix\n  [/^(.*)\\.js(\\.flow)?$/, '$1'],\n  // strip .android/.ios/.native/.web suffix\n  [/^(.*)\\.(android|ios|native|web)$/, '$1'],\n];\n\nconst haste = {\n  /*\n   * @return {string|void} hasteName for module at filePath; or undefined if\n   *                       filePath is not a haste module\n   */\n  getHasteName(\n    filePath/*: string*/,\n    sourceCode/* : ?string*/\n  )/*: (string | void)*/ {\n    if (!isHastePath(filePath)) {\n      return undefined;\n    }\n\n    const hasteName = NAME_REDUCERS.reduce(\n      (name, [pattern, replacement]) => name.replace(pattern, replacement),\n      filePath\n    );\n\n    return hasteName;\n  },\n};\n\nfunction isHastePath(filePath/*: string*/)/*: bool*/ {\n  if (!filePath.endsWith('.js') && !filePath.endsWith('.js.flow')) {\n    return false;\n  }\n\n  if (!filePath.startsWith(ROOT)) {\n    return false;\n  }\n\n  filePath = filePath.substr(ROOT.length + 1);\n  if (BLACKLISTED_PATTERNS.some(pattern => pattern.test(filePath))) {\n    return false;\n  }\n  return WHITELISTED_PREFIXES.some(prefix => filePath.startsWith(prefix));\n}\n\nmodule.exports = haste;\n"
  },
  {
    "path": "scripts/jest/preprocessor.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nvar babel = require('@babel/core');\nvar createCacheKeyFunction = require('fbjs-scripts/jest/createCacheKeyFunction');\nvar fbjsConfigurePreset = require('babel-preset-fbjs/configure');\nvar moduleMap = require('../module-map');\nvar path = require('path');\n\nmodule.exports = {\n  process(src, filename) {\n    var options = {\n      presets: [fbjsConfigurePreset({rewriteModules: {map: moduleMap}})],\n      plugins: [\n        require('@babel/plugin-proposal-nullish-coalescing-operator'),\n        require('@babel/plugin-proposal-optional-chaining')\n      ],\n      filename: filename,\n      retainLines: true,\n    };\n    return babel.transform(src, options).code;\n  },\n\n  getCacheKey: createCacheKeyFunction([\n    __filename,\n    path.join(\n      __dirname,\n      '..',\n      '..',\n      'node_modules',\n      'fbjs',\n      'package.json'\n    ),\n    path.join(\n      __dirname,\n      '..',\n      '..',\n      'node_modules',\n      'fbjs-scripts',\n      'package.json'\n    ),\n    path.join(\n      __dirname,\n      '..',\n      '..',\n      'node_modules',\n      'babel-preset-fbjs',\n      'package.json'\n    ),\n    path.join(\n      __dirname,\n      '..',\n      'module-map.js'\n    ),\n  ]),\n};\n"
  },
  {
    "path": "scripts/jest/shims.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @format\n */\n\n// used for testing react fiber\nglobal.requestAnimationFrame = (callback) => global.setTimeout(callback, 0);\n"
  },
  {
    "path": "scripts/module-map.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nmodule.exports = Object.assign(\n  {\n    immutable: 'immutable',\n    React: 'react',\n    react: 'react',\n    ReactDOM: 'react-dom',\n    'react-dom': 'react-dom',\n    ReactDOMComet: 'react-dom',\n    'object-assign': 'object-assign',\n\n    ReactTestUtils: 'react-dom/lib/ReactTestUtils',\n    reactComponentExpect: 'react-dom/lib/reactComponentExpect',\n  },\n  require('fbjs/module-map'),\n  require('fbjs-scripts/third-party-module-map'),\n);\n"
  },
  {
    "path": "src/.flowconfig",
    "content": "[ignore]\n.*/__tests__.*\n.*/react/node_modules/.*\n.*/react-dom/node_modules/.*\n.*/fbjs/node_modules/.*\n.*/node_modules/invariant/.*\n.*/node_modules/fbjs/lib/emptyFunction.js.flow\n\n[include]\n../node_modules/fbjs/lib/\n../node_modules/immutable\n../node_modules/react\n../node_modules/react-dom/\n\n[libs]\n../node_modules/fbjs/flow/lib\n./flowlib/\n\n[options]\nmodule.system=haste\nmodule.system.haste.use_name_reducers=true\n# keep the following in sync with server/haste/hasteImpl.js\n# get basename\nmodule.system.haste.name_reducers='^.*/\\([a-zA-Z0-9$_.-]+\\.js\\(\\.flow\\)?\\)$' -> '\\1'\n# strip .js or .js.flow suffix\nmodule.system.haste.name_reducers='^\\(.*\\)\\.js\\(\\.flow\\)?$' -> '\\1'\nmodule.system.haste.paths.includes=<PROJECT_ROOT>/.*\nmodule.system.haste.paths.includes=.*/node_modules/fbjs/lib/.*\nmodule.system.haste.paths.excludes=.*/__tests__/.*\nmodule.system.haste.paths.excludes=.*/react/node_modules/.*\nmodule.system.haste.paths.excludes=.*/react-dom/node_modules/.*\nmodule.system.haste.paths.excludes=.*/fbjs/node_modules/.*\nmodule.system.haste.paths.excludes=.*/node_modules/invariant/.*\n\nesproposal.class_static_fields=enable\nesproposal.optional_chaining=enable\nsuppress_type=$FlowIssue\n; suppress_comment=\\\\(.\\\\|\\n\\\\)*\\\\$FlowFixMe\\\\($\\\\|[^(]\\\\|(\\\\(>=0\\\\.\\\\(2[0-8]\\\\|1[0-9]\\\\|[0-9]\\\\).[0-9]\\\\)? *\\\\).*\\n\n; suppress_comment=\\\\(.\\\\|\\n\\\\)*\\\\$FlowExpectedError\nmodule.name_mapper='ReactDOMComet' -> 'react-dom'\n\n[strict]\ndeprecated-type\nsketchy-null\nunclear-type\nunsafe-getters-setters\n; Can't enable these- immutable.js raises errors\n; untyped-import\n; untyped-type-import\n; Can't enable this one- getTextContentFromFiles requires invariant.\n; The publicly-available fbjs version of invariant isn't flow strict.\n; nonstrict-import\n\n[version]\n^0.130.0\n"
  },
  {
    "path": "src/Draft.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n */\n\n'use strict';\n\nconst AtomicBlockUtils = require('AtomicBlockUtils');\nconst BlockMapBuilder = require('BlockMapBuilder');\nconst CharacterMetadata = require('CharacterMetadata');\nconst CompositeDraftDecorator = require('CompositeDraftDecorator');\nconst ContentBlock = require('ContentBlock');\nconst ContentState = require('ContentState');\nconst DefaultDraftBlockRenderMap = require('DefaultDraftBlockRenderMap');\nconst DefaultDraftInlineStyle = require('DefaultDraftInlineStyle');\nconst DraftEditor = require('DraftEditor.react');\nconst DraftEditorBlock = require('DraftEditorBlock.react');\nconst DraftEntity = require('DraftEntity');\nconst DraftEntityInstance = require('DraftEntityInstance');\nconst DraftModifier = require('DraftModifier');\nconst EditorState = require('EditorState');\nconst KeyBindingUtil = require('KeyBindingUtil');\nconst RawDraftContentState = require('RawDraftContentState');\nconst RichTextEditorUtil = require('RichTextEditorUtil');\nconst SelectionState = require('SelectionState');\n\nconst convertFromDraftStateToRaw = require('convertFromDraftStateToRaw');\nconst convertFromHTML = require('convertFromHTMLToContentBlocks');\nconst convertFromRawToDraftState = require('convertFromRawToDraftState');\nconst generateRandomKey = require('generateRandomKey');\nconst getDefaultKeyBinding = require('getDefaultKeyBinding');\nconst getVisibleSelectionRect = require('getVisibleSelectionRect');\n\nconst DraftPublic = {\n  Editor: DraftEditor,\n  EditorBlock: DraftEditorBlock,\n  EditorState,\n\n  CompositeDecorator: CompositeDraftDecorator,\n  Entity: DraftEntity,\n  EntityInstance: DraftEntityInstance,\n\n  BlockMapBuilder,\n  CharacterMetadata,\n  ContentBlock,\n  ContentState,\n  RawDraftContentState,\n  SelectionState,\n\n  AtomicBlockUtils,\n  KeyBindingUtil,\n  Modifier: DraftModifier,\n  RichUtils: RichTextEditorUtil,\n\n  DefaultDraftBlockRenderMap,\n  DefaultDraftInlineStyle,\n\n  convertFromHTML,\n  convertFromRaw: convertFromRawToDraftState,\n  convertToRaw: convertFromDraftStateToRaw,\n  genKey: generateRandomKey,\n  getDefaultKeyBinding,\n  getVisibleSelectionRect,\n};\n\nmodule.exports = DraftPublic;\n"
  },
  {
    "path": "src/NonASCIIStringSnapshotSerializer.js",
    "content": "/**\n * (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.\n *\n * @flow strict-local\n * @format\n * @oncall ads_integration_management\n */\n\n'use strict';\n\nconst MAX_ASCII_CHARACTER = 127;\n\n/**\n * Serializes strings with non-ASCII characters to their Unicode escape\n * sequences (eg. \\u2022), to avoid hitting this lint rule:\n * \"Source code should only include printable US-ASCII bytes\"\n */\nconst NonASCIIStringSnapshotSerializer = {\n  test(val: mixed): boolean {\n    if (typeof val !== 'string') {\n      return false;\n    }\n    for (let i = 0; i < val.length; i++) {\n      if (val.charCodeAt(i) > MAX_ASCII_CHARACTER) {\n        return true;\n      }\n    }\n    return false;\n  },\n\n  print: (val: string): string => {\n    return (\n      '\"' +\n      val\n        .split('')\n        .map((char) => {\n          const code = char.charCodeAt(0);\n          return code > MAX_ASCII_CHARACTER\n            ? '\\\\u' + code.toString(16).padStart(4, '0')\n            : char;\n        })\n        .join('')\n        // Keep the same behaviour as Jest's regular string snapshot\n        // serialization, which escapes double quotes.\n        .replace(/\"/g, '\\\\\"') +\n      '\"'\n    );\n  },\n};\n\nmodule.exports = NonASCIIStringSnapshotSerializer;\n"
  },
  {
    "path": "src/__mocks__/generateRandomKey.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @format\n */\n\n'use strict';\n\nlet count = 0;\n\nfunction generateRandomKey() {\n  return `key${count++}`;\n}\n\nmodule.exports = generateRandomKey;\n"
  },
  {
    "path": "src/component/base/DraftEditor.css",
    "content": "/**\n * (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @providesModule DraftEditor\n * @format\n */\n\n/**\n * We inherit the height of the container by default\n */\n.DraftEditor/root,\n.DraftEditor/editorContainer,\n.public/DraftEditor/content {\n  height: inherit;\n  text-align: initial;\n}\n\n.public/DraftEditor/content[contenteditable='true'] {\n  -webkit-user-modify: read-write-plaintext-only;\n}\n\n.DraftEditor/root {\n  position: relative;\n}\n\n/**\n * Zero-opacity background used to allow focus in IE. Otherwise, clicks\n * fall through to the placeholder.\n */\n.DraftEditor/editorContainer {\n  background-color: rgba(255, 255, 255, 0);\n  position: relative;\n  z-index: 1;\n}\n\n.safari .DraftEditor/editorContainer {\n  /* Repair mysterious missing Safari cursor */\n  border-left: 0.1px solid transparent;\n}\n\n.public/DraftEditor/block {\n  position: relative;\n}\n\n.DraftEditor/alignLeft .public/DraftStyleDefault/block {\n  text-align: left;\n}\n\n.DraftEditor/alignLeft .public/DraftEditorPlaceholder/root {\n  left: 0;\n  text-align: left;\n}\n\n.DraftEditor/alignCenter .public/DraftStyleDefault/block {\n  text-align: center;\n}\n\n.DraftEditor/alignCenter .public/DraftEditorPlaceholder/root {\n  margin: 0 auto;\n  text-align: center;\n  width: 100%;\n}\n\n.DraftEditor/alignRight .public/DraftStyleDefault/block {\n  text-align: right;\n}\n\n.DraftEditor/alignRight .public/DraftEditorPlaceholder/root {\n  right: 0;\n  text-align: right;\n}\n"
  },
  {
    "path": "src/component/base/DraftEditor.react.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n * @preventMunge\n */\n\n'use strict';\n\nimport type {BlockMap} from 'BlockMap';\nimport type {DraftEditorModes} from 'DraftEditorModes';\nimport type {DraftEditorDefaultProps, DraftEditorProps} from 'DraftEditorProps';\nimport type {DraftScrollPosition} from 'DraftScrollPosition';\n\nconst DefaultDraftBlockRenderMap = require('DefaultDraftBlockRenderMap');\nconst DefaultDraftInlineStyle = require('DefaultDraftInlineStyle');\nconst DraftEditorCompositionHandler = require('DraftEditorCompositionHandler');\nconst DraftEditorContents = require('DraftEditorContents.react');\nconst DraftEditorDragHandler = require('DraftEditorDragHandler');\nconst DraftEditorEditHandler = require('DraftEditorEditHandler');\nconst flushControlled = require('DraftEditorFlushControlled');\nconst DraftEditorPlaceholder = require('DraftEditorPlaceholder.react');\nconst DraftEffects = require('DraftEffects');\nconst EditorState = require('EditorState');\nconst Scroll = require('Scroll');\nconst Style = require('Style');\nconst UserAgent = require('UserAgent');\n\nconst cx = require('cx');\nconst generateRandomKey = require('generateRandomKey');\nconst getDefaultKeyBinding = require('getDefaultKeyBinding');\nconst getScrollPosition = require('getScrollPosition');\nconst gkx = require('gkx');\nconst invariant = require('invariant');\nconst isHTMLElement = require('isHTMLElement');\nconst nullthrows = require('nullthrows');\nconst React = require('react');\n\nconst isIE = UserAgent.isBrowser('IE');\n\n// IE does not support the `input` event on contentEditable, so we can't\n// observe spellcheck behavior.\nconst allowSpellCheck = !isIE;\n\n// Define a set of handler objects to correspond to each possible `mode`\n// of editor behavior.\nconst handlerMap = {\n  edit: DraftEditorEditHandler,\n  composite: DraftEditorCompositionHandler,\n  drag: DraftEditorDragHandler,\n  cut: null,\n  render: null,\n};\n\ntype State = {contentsKey: number};\n\nlet didInitODS = false;\n\nclass UpdateDraftEditorFlags extends React.Component<{\n  editor: DraftEditor,\n  editorState: EditorState,\n}> {\n  render(): React.Node {\n    return null;\n  }\n  componentDidMount(): mixed {\n    this._update();\n  }\n  componentDidUpdate(): mixed {\n    this._update();\n  }\n  _update() {\n    const editor = this.props.editor;\n    /**\n     * Sometimes a render triggers a 'focus' or other event, and that will\n     * schedule a second render pass.\n     * In order to make sure the second render pass gets the latest editor\n     * state, we update it here.\n     * Example:\n     * render #1\n     * +\n     * |\n     * | cWU -> Nothing ... latestEditorState = STALE_STATE :(\n     * |\n     * | render -> this.props.editorState = FRESH_STATE\n     * | +         *and* set latestEditorState = FRESH_STATE\n     *   |\n     * | |\n     * | +--> triggers 'focus' event, calling 'handleFocus' with latestEditorState\n     * |                                                +\n     * |                                                |\n     * +>cdU -> latestEditorState = FRESH_STATE         | the 'handleFocus' call schedules render #2\n     *                                                  | with latestEditorState, which is FRESH_STATE\n     *                                                  |\n     * render #2 <--------------------------------------+\n     * +\n     * |\n     * | cwU -> nothing updates\n     * |\n     * | render -> this.props.editorState = FRESH_STATE which was passed in above\n     * |\n     * +>cdU fires and resets latestEditorState = FRESH_STATE\n     * ---\n     * Note that if we don't set latestEditorState in 'render' in the above\n     * diagram, then STALE_STATE gets passed to render #2.\n     */\n    editor._latestEditorState = this.props.editorState;\n\n    /**\n     * The reason we set this 'blockSelectEvents' flag is that  IE will fire a\n     * 'selectionChange' event when we programmatically change the selection,\n     * meaning it would trigger a new select event while we are in the middle\n     * of updating.\n     * We found that the 'selection.addRange' was what triggered the stray\n     * selectionchange event in IE.\n     * To be clear - we have not been able to reproduce specific bugs related\n     * to this stray selection event, but have recorded logs that some\n     * conditions do cause it to get bumped into during editOnSelect.\n     */\n    editor._blockSelectEvents = true;\n  }\n}\n\nconst EDITOR_ID_PLACEHOLDER = '{{editor_id_placeholder}}';\n\n/**\n * `DraftEditor` is the root editor component. It composes a `contentEditable`\n * div, and provides a wide variety of useful function props for managing the\n * state of the editor. See `DraftEditorProps` for details.\n */\nclass DraftEditor extends React.Component<DraftEditorProps, State> {\n  static defaultProps: DraftEditorDefaultProps = {\n    ariaDescribedBy: EDITOR_ID_PLACEHOLDER,\n    blockRenderMap: DefaultDraftBlockRenderMap,\n    blockRendererFn() {\n      return null;\n    },\n    blockStyleFn() {\n      return '';\n    },\n    keyBindingFn: getDefaultKeyBinding,\n    readOnly: false,\n    spellCheck: false,\n    stripPastedStyles: false,\n  };\n\n  _blockSelectEvents: boolean;\n  _clipboard: ?BlockMap;\n  _handler: ?Object;\n  _dragCount: number;\n  _internalDrag: boolean = false;\n  _editorKey: string;\n  _placeholderAccessibilityID: string;\n  _latestEditorState: EditorState;\n  _latestCommittedEditorState: EditorState;\n  _pendingStateFromBeforeInput: void | EditorState;\n\n  /**\n   * Define proxies that can route events to the current handler.\n   */\n  _onBeforeInput: Function;\n  _onBlur: Function;\n  _onCharacterData: Function;\n  _onCompositionEnd: Function;\n  _onCompositionStart: Function;\n  _onCopy: Function;\n  _onCut: Function;\n  _onDragEnd: Function;\n  _onDragOver: Function;\n  _onDragStart: Function;\n  _onDrop: Function;\n  _onInput: Function;\n  _onFocus: Function;\n  _onKeyDown: Function;\n  _onKeyPress: Function;\n  _onKeyUp: Function;\n  _onMouseDown: Function;\n  _onMouseUp: Function;\n  _onPaste: Function;\n  _onSelect: Function;\n\n  editor: ?HTMLElement;\n  editorContainer: ?HTMLElement;\n  getEditorKey: () => string;\n  // See `restoreEditorDOM()`.\n  state: State = {contentsKey: 0};\n\n  constructor(props: DraftEditorProps) {\n    super(props);\n\n    this._blockSelectEvents = false;\n    this._clipboard = null;\n    this._handler = null;\n    this._dragCount = 0;\n    this._editorKey = props.editorKey || generateRandomKey();\n    this._placeholderAccessibilityID = 'placeholder-' + this._editorKey;\n    this._latestEditorState = props.editorState;\n    this._latestCommittedEditorState = props.editorState;\n\n    this._onBeforeInput = this._buildHandler('onBeforeInput');\n    this._onBlur = this._buildHandler('onBlur');\n    this._onCharacterData = this._buildHandler('onCharacterData');\n    this._onCompositionEnd = this._buildHandler('onCompositionEnd');\n    this._onCompositionStart = this._buildHandler('onCompositionStart');\n    this._onCopy = this._buildHandler('onCopy');\n    this._onCut = this._buildHandler('onCut');\n    this._onDragEnd = this._buildHandler('onDragEnd');\n    this._onDragOver = this._buildHandler('onDragOver');\n    this._onDragStart = this._buildHandler('onDragStart');\n    this._onDrop = this._buildHandler('onDrop');\n    this._onInput = this._buildHandler('onInput');\n    this._onFocus = this._buildHandler('onFocus');\n    this._onKeyDown = this._buildHandler('onKeyDown');\n    this._onKeyPress = this._buildHandler('onKeyPress');\n    this._onKeyUp = this._buildHandler('onKeyUp');\n    this._onMouseDown = this._buildHandler('onMouseDown');\n    this._onMouseUp = this._buildHandler('onMouseUp');\n    this._onPaste = this._buildHandler('onPaste');\n    this._onSelect = this._buildHandler('onSelect');\n\n    this.getEditorKey = () => this._editorKey;\n\n    if (__DEV__) {\n      [\n        'onDownArrow',\n        'onEscape',\n        'onLeftArrow',\n        'onRightArrow',\n        'onTab',\n        'onUpArrow',\n      ].forEach(propName => {\n        if (props.hasOwnProperty(propName)) {\n          // eslint-disable-next-line fb-www/no-console\n          console.warn(\n            `Supplying an \\`${propName}\\` prop to \\`DraftEditor\\` has ` +\n              'been deprecated. If your handler needs access to the keyboard ' +\n              'event, supply a custom `keyBindingFn` prop that falls back to ' +\n              'the default one (eg. https://is.gd/wHKQ3W).',\n          );\n        }\n      });\n    }\n  }\n\n  /**\n   * Build a method that will pass the event to the specified handler method.\n   * This allows us to look up the correct handler function for the current\n   * editor mode, if any has been specified.\n   */\n  _buildHandler(eventName: string): Function {\n    // Wrap event handlers in `flushControlled`. In sync mode, this is\n    // effectively a no-op. In async mode, this ensures all updates scheduled\n    // inside the handler are flushed before React yields to the browser.\n    return e => {\n      if (!this.props.readOnly) {\n        const method = this._handler && this._handler[eventName];\n        if (method) {\n          if (flushControlled) {\n            flushControlled(() => method(this, e));\n          } else {\n            method(this, e);\n          }\n        }\n      }\n    };\n  }\n\n  _handleEditorContainerRef: (HTMLElement | null) => void = (\n    node: HTMLElement | null,\n  ): void => {\n    this.editorContainer = node;\n    // Instead of having a direct ref on the child, we'll grab it here.\n    // This is safe as long as the rendered structure is static (which it is).\n    // This lets the child support ref={props.editorRef} without merging refs.\n    this.editor = node !== null ? (node: any).firstChild : null;\n  };\n\n  _showPlaceholder(): boolean {\n    return (\n      !!this.props.placeholder &&\n      !this.props.editorState.isInCompositionMode() &&\n      !this.props.editorState.getCurrentContent().hasText()\n    );\n  }\n\n  _renderPlaceholder(): React.Node {\n    if (this._showPlaceholder()) {\n      const placeHolderProps = {\n        ariaHidden: this.props.placeholderAriaHidden,\n        accessibilityID: this._placeholderAccessibilityID,\n        className: this.props.placeholderClassName,\n        editorState: this.props.editorState,\n        text: nullthrows(this.props.placeholder),\n        textAlignment: this.props.textAlignment,\n      };\n\n      /* $FlowFixMe[incompatible-type] (>=0.112.0 site=www,mobile) This comment\n       * suppresses an error found when Flow v0.112 was deployed. To see the\n       * error delete this comment and run Flow. */\n      return <DraftEditorPlaceholder {...placeHolderProps} />;\n    }\n    return null;\n  }\n\n  /**\n   * returns ariaDescribedBy prop with EDITOR_ID_PLACEHOLDER replaced with\n   * the DOM id of the placeholder (if it exists)\n   * @returns aria-describedby attribute value\n   */\n  _renderARIADescribedBy(): ?string {\n    const describedBy = this.props.ariaDescribedBy || '';\n    if (this.props.placeholderAriaHidden) {\n      return describedBy === EDITOR_ID_PLACEHOLDER ? undefined : describedBy;\n    }\n    const placeholderID = this._showPlaceholder()\n      ? this._placeholderAccessibilityID\n      : '';\n    return (\n      describedBy.replace(EDITOR_ID_PLACEHOLDER, placeholderID) || undefined\n    );\n  }\n\n  render(): React.Node {\n    const {\n      blockRenderMap,\n      blockRendererFn,\n      blockStyleFn,\n      customStyleFn,\n      customStyleMap,\n      editorState,\n      preventScroll,\n      readOnly,\n      textAlignment,\n      textDirectionality,\n    } = this.props;\n\n    const rootClass = cx({\n      'DraftEditor/root': true,\n      'DraftEditor/alignLeft': textAlignment === 'left',\n      'DraftEditor/alignRight': textAlignment === 'right',\n      'DraftEditor/alignCenter': textAlignment === 'center',\n    });\n\n    const contentStyle = {\n      outline: 'none',\n      // fix parent-draggable Safari bug. #1326\n      userSelect: 'text',\n      WebkitUserSelect: 'text',\n      whiteSpace: 'pre-wrap',\n      wordWrap: 'break-word',\n    };\n\n    // The aria-expanded and aria-haspopup properties should only be rendered\n    // for a combobox.\n    /* $FlowFixMe[prop-missing] (>=0.68.0 site=www,mobile) This comment\n     * suppresses an error found when Flow v0.68 was deployed. To see the error\n     * delete this comment and run Flow. */\n    const ariaRole = this.props.role || 'textbox';\n    const ariaExpanded =\n      ariaRole === 'combobox' ? !!this.props.ariaExpanded : null;\n\n    const editorContentsProps = {\n      blockRenderMap,\n      blockRendererFn,\n      blockStyleFn,\n      customStyleMap: {\n        ...DefaultDraftInlineStyle,\n        ...customStyleMap,\n      },\n      customStyleFn,\n      editorKey: this._editorKey,\n      editorState,\n      preventScroll,\n      textDirectionality,\n    };\n\n    const contentClassName =\n      this.props.contentClassName != null\n        ? this.props.contentClassName + ' '\n        : '';\n\n    return (\n      <div className={rootClass}>\n        {this._renderPlaceholder()}\n        <div\n          className={cx('DraftEditor/editorContainer')}\n          ref={this._handleEditorContainerRef}>\n          {/* Note: _handleEditorContainerRef assumes this div won't move: */}\n          <div\n            aria-activedescendant={\n              readOnly ? null : this.props.ariaActiveDescendantID\n            }\n            aria-autocomplete={readOnly ? null : this.props.ariaAutoComplete}\n            aria-controls={readOnly ? null : this.props.ariaControls}\n            aria-describedby={this._renderARIADescribedBy()}\n            aria-expanded={readOnly ? null : ariaExpanded}\n            aria-label={this.props.ariaLabel ?? this.props.placeholder}\n            aria-labelledby={this.props.ariaLabelledBy}\n            aria-multiline={this.props.ariaMultiline}\n            aria-owns={readOnly ? null : this.props.ariaOwneeID}\n            aria-required={this.props.ariaRequired}\n            autoCapitalize={this.props.autoCapitalize}\n            autoComplete={this.props.autoComplete}\n            autoCorrect={this.props.autoCorrect}\n            className={\n              // eslint-disable-next-line fb-www/cx-concat\n              contentClassName +\n              cx({\n                // Chrome's built-in translation feature mutates the DOM in ways\n                // that Draft doesn't expect (ex: adding <font> tags inside\n                // DraftEditorLeaf spans) and causes problems. We add notranslate\n                // here which makes its autotranslation skip over this subtree.\n                notranslate: !readOnly,\n                'public/DraftEditor/content': true,\n              })\n            }\n            contentEditable={!readOnly}\n            data-testid={this.props.webDriverTestID}\n            onBeforeInput={this._onBeforeInput}\n            onBlur={this._onBlur}\n            onCompositionEnd={this._onCompositionEnd}\n            onCompositionStart={this._onCompositionStart}\n            onCopy={this._onCopy}\n            onCut={this._onCut}\n            onDragEnd={this._onDragEnd}\n            onDragEnter={this.onDragEnter}\n            onDragLeave={this.onDragLeave}\n            onDragOver={this._onDragOver}\n            onDragStart={this._onDragStart}\n            onDrop={this._onDrop}\n            onFocus={this._onFocus}\n            onInput={this._onInput}\n            onKeyDown={this._onKeyDown}\n            onKeyPress={this._onKeyPress}\n            onKeyUp={this._onKeyUp}\n            onMouseDown={this._onMouseDown}\n            onMouseUp={this._onMouseUp}\n            onPaste={this._onPaste}\n            onSelect={this._onSelect}\n            ref={this.props.editorRef}\n            role={readOnly ? null : ariaRole}\n            spellCheck={allowSpellCheck && this.props.spellCheck}\n            style={contentStyle}\n            suppressContentEditableWarning\n            tabIndex={this.props.tabIndex}>\n            {/*\n              Needs to come earlier in the tree as a sibling (not ancestor) of\n              all DraftEditorLeaf nodes so it's first in postorder traversal.\n            */}\n            <UpdateDraftEditorFlags editor={this} editorState={editorState} />\n            <DraftEditorContents\n              {...editorContentsProps}\n              key={'contents' + this.state.contentsKey}\n            />\n          </div>\n        </div>\n      </div>\n    );\n  }\n\n  componentDidMount(): void {\n    this._blockSelectEvents = false;\n    if (!didInitODS && gkx('draft_ods_enabled')) {\n      didInitODS = true;\n      DraftEffects.initODS();\n    }\n    this.setMode('edit');\n\n    /**\n     * IE has a hardcoded \"feature\" that attempts to convert link text into\n     * anchors in contentEditable DOM. This breaks the editor's expectations of\n     * the DOM, and control is lost. Disable it to make IE behave.\n     * See: http://blogs.msdn.com/b/ieinternals/archive/2010/09/15/\n     * ie9-beta-minor-change-list.aspx\n     */\n    if (isIE) {\n      // editor can be null after mounting\n      // https://stackoverflow.com/questions/44074747/componentdidmount-called-before-ref-callback\n      if (!this.editor) {\n        global.execCommand('AutoUrlDetect', false, false);\n      } else {\n        this.editor.ownerDocument.execCommand('AutoUrlDetect', false, false);\n      }\n    }\n  }\n\n  componentDidUpdate(): void {\n    this._blockSelectEvents = false;\n    this._latestEditorState = this.props.editorState;\n    this._latestCommittedEditorState = this.props.editorState;\n  }\n\n  /**\n   * Used via `this.focus()`.\n   *\n   * Force focus back onto the editor node.\n   *\n   * We attempt to preserve scroll position when focusing. You can also pass\n   * a specified scroll position (for cases like `cut` behavior where it should\n   * be restored to a known position).\n   */\n  // eslint-disable-next-line fb-www/extra-arrow-initializer\n  focus: (scrollPosition?: DraftScrollPosition) => void = (\n    scrollPosition?: DraftScrollPosition,\n  ): void => {\n    const {editorState} = this.props;\n    const alreadyHasFocus = editorState.getSelection().getHasFocus();\n    const editorNode = this.editor;\n\n    if (!editorNode) {\n      // once in a while people call 'focus' in a setTimeout, and the node has\n      // been deleted, so it can be null in that case.\n      return;\n    }\n\n    const scrollParent = Style.getScrollParent(editorNode);\n    const {x, y} = scrollPosition || getScrollPosition(scrollParent);\n\n    invariant(isHTMLElement(editorNode), 'editorNode is not an HTMLElement');\n\n    editorNode.focus({preventScroll: true});\n\n    // Restore scroll position\n    if (scrollParent === window) {\n      window.scrollTo(x, y);\n    } else {\n      Scroll.setTop(scrollParent, y);\n    }\n\n    // On Chrome and Safari, calling focus on contenteditable focuses the\n    // cursor at the first character. This is something you don't expect when\n    // you're clicking on an input element but not directly on a character.\n    // Put the cursor back where it was before the blur.\n    if (!alreadyHasFocus) {\n      this.update(\n        EditorState.forceSelection(editorState, editorState.getSelection()),\n      );\n    }\n  };\n\n  // eslint-disable-next-line fb-www/extra-arrow-initializer\n  blur: () => void = (): void => {\n    const editorNode = this.editor;\n    if (!editorNode) {\n      return;\n    }\n    invariant(isHTMLElement(editorNode), 'editorNode is not an HTMLElement');\n    editorNode.blur();\n  };\n\n  /**\n   * Used via `this.setMode(...)`.\n   *\n   * Set the behavior mode for the editor component. This switches the current\n   * handler module to ensure that DOM events are managed appropriately for\n   * the active mode.\n   */\n  // eslint-disable-next-line fb-www/extra-arrow-initializer\n  setMode: DraftEditorModes => void = (mode: DraftEditorModes): void => {\n    const {onPaste, onCut, onCopy} = this.props;\n    const editHandler = {...handlerMap.edit};\n\n    if (onPaste) {\n      /* $FlowFixMe[incompatible-type] (>=0.117.0 site=www,mobile) This comment\n       * suppresses an error found when Flow v0.117 was deployed. To see the\n       * error delete this comment and run Flow. */\n      editHandler.onPaste = onPaste;\n    }\n\n    if (onCut) {\n      editHandler.onCut = onCut;\n    }\n\n    if (onCopy) {\n      editHandler.onCopy = onCopy;\n    }\n\n    const handler = {\n      ...handlerMap,\n      edit: editHandler,\n    };\n    this._handler = handler[mode];\n  };\n\n  // eslint-disable-next-line fb-www/extra-arrow-initializer\n  exitCurrentMode: () => void = (): void => {\n    this.setMode('edit');\n  };\n\n  /**\n   * Used via `this.restoreEditorDOM()`.\n   *\n   * Force a complete re-render of the DraftEditorContents based on the current\n   * EditorState. This is useful when we know we are going to lose control of\n   * the DOM state (cut command, IME) and we want to make sure that\n   * reconciliation occurs on a version of the DOM that is synchronized with\n   * our EditorState.\n   */\n  // eslint-disable-next-line fb-www/extra-arrow-initializer\n  restoreEditorDOM: (scrollPosition?: DraftScrollPosition) => void = (\n    scrollPosition?: DraftScrollPosition,\n  ): void => {\n    // Wrap state updates in `flushControlled`. In sync mode, this is\n    // effectively a no-op. In async mode, this ensures all updates scheduled\n    // inside are flushed before React yields to the browser.\n    if (flushControlled) {\n      flushControlled(() =>\n        this.setState({contentsKey: this.state.contentsKey + 1}, () => {\n          this.focus(scrollPosition);\n        }),\n      );\n    } else {\n      this.setState({contentsKey: this.state.contentsKey + 1}, () => {\n        this.focus(scrollPosition);\n      });\n    }\n  };\n\n  /**\n   * Used via `this.setClipboard(...)`.\n   *\n   * Set the clipboard state for a cut/copy event.\n   */\n  // eslint-disable-next-line fb-www/extra-arrow-initializer\n  setClipboard: (?BlockMap) => void = (clipboard: ?BlockMap): void => {\n    this._clipboard = clipboard;\n  };\n\n  /**\n   * Used via `this.getClipboard()`.\n   *\n   * Retrieve the clipboard state for a cut/copy event.\n   */\n  // eslint-disable-next-line fb-www/extra-arrow-initializer\n  getClipboard: () => ?BlockMap = (): ?BlockMap => {\n    return this._clipboard;\n  };\n\n  /**\n   * Used via `this.update(...)`.\n   *\n   * Propagate a new `EditorState` object to higher-level components. This is\n   * the method by which event handlers inform the `DraftEditor` component of\n   * state changes. A component that composes a `DraftEditor` **must** provide\n   * an `onChange` prop to receive state updates passed along from this\n   * function.\n   */\n  // eslint-disable-next-line fb-www/extra-arrow-initializer\n  update: EditorState => void = (editorState: EditorState): void => {\n    const onChange = this.props.onChange;\n    this._latestEditorState = editorState;\n    // Wrap state updates in `flushControlled`. In sync mode, this is\n    // effectively a no-op. In async mode, this ensures all updates scheduled\n    // inside are flushed before React yields to the browser.\n    if (flushControlled) {\n      flushControlled(() => onChange(editorState));\n    } else {\n      onChange(editorState);\n    }\n  };\n\n  /**\n   * Used in conjunction with `onDragLeave()`, by counting the number of times\n   * a dragged element enters and leaves the editor (or any of its children),\n   * to determine when the dragged element absolutely leaves the editor.\n   */\n  onDragEnter: () => void = (): void => {\n    this._dragCount++;\n  };\n\n  /**\n   * See `onDragEnter()`.\n   */\n  onDragLeave: () => void = (): void => {\n    this._dragCount--;\n    if (this._dragCount === 0) {\n      this.exitCurrentMode();\n    }\n  };\n}\n\nmodule.exports = DraftEditor;\n"
  },
  {
    "path": "src/component/base/DraftEditorFlushControlled.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\nconst ReactDOMComet = require('ReactDOMComet');\n\nconst flushControlled: void | ((fn: () => void) => void) =\n  ReactDOMComet.unstable_flushControlled;\n\nmodule.exports = flushControlled;\n"
  },
  {
    "path": "src/component/base/DraftEditorPlaceholder.css",
    "content": "/**\n * (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @providesModule DraftEditorPlaceholder\n * @format\n */\n\n.public/DraftEditorPlaceholder/root {\n  color: var(fig-secondary-text);\n  position: absolute;\n  width: 100%;\n  z-index: 1;\n}\n\n.public/DraftEditorPlaceholder/hasFocus {\n  color: var(fig-light-20);\n}\n\n.DraftEditorPlaceholder/hidden {\n  display: none;\n}\n"
  },
  {
    "path": "src/component/base/DraftEditorPlaceholder.react.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {DraftTextAlignment} from 'DraftTextAlignment';\nimport type EditorState from 'EditorState';\n\nconst cx = require('cx');\nconst React = require('react');\nconst shallowEqual = require('shallowEqual');\n\ntype Props = {\n  ariaHidden?: boolean,\n  accessibilityID: string,\n  className?: string,\n  editorState: EditorState,\n  text: string,\n  textAlignment: DraftTextAlignment,\n  ...\n};\n\n/**\n * This component is responsible for rendering placeholder text for the\n * `DraftEditor` component.\n *\n * Override placeholder style via CSS.\n */\nclass DraftEditorPlaceholder extends React.Component<Props> {\n  shouldComponentUpdate(nextProps: Props): boolean {\n    const {editorState, ...otherProps} = this.props;\n    const {editorState: nextEditorState, ...nextOtherProps} = nextProps;\n    return (\n      editorState.getSelection().getHasFocus() !==\n        nextEditorState.getSelection().getHasFocus() ||\n      !shallowEqual(otherProps, nextOtherProps)\n    );\n  }\n\n  render(): React.Node {\n    const innerClassName =\n      // We can't use joinClasses since the fbjs flow definition is wrong. Using\n      // cx to concatenate is rising issues with haste internally.\n      // eslint-disable-next-line fb-www/cx-concat\n      cx('public/DraftEditorPlaceholder/inner') +\n      (this.props.className != null ? ` ${this.props.className}` : '');\n\n    return (\n      <div\n        aria-hidden={this.props.ariaHidden}\n        className={cx({\n          'public/DraftEditorPlaceholder/root': true,\n          'public/DraftEditorPlaceholder/hasFocus': this.props.editorState\n            .getSelection()\n            .getHasFocus(),\n        })}>\n        <div\n          className={innerClassName}\n          id={this.props.accessibilityID}\n          style={{\n            whiteSpace: 'pre-wrap',\n          }}>\n          {this.props.text}\n        </div>\n      </div>\n    );\n  }\n}\n\nmodule.exports = DraftEditorPlaceholder;\n"
  },
  {
    "path": "src/component/base/DraftEditorProps.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type {DraftBlockRenderMap} from 'DraftBlockRenderMap';\nimport type {DraftDragType} from 'DraftDragType';\nimport type DraftEditor from 'DraftEditor.react';\nimport type {DraftEditorCommand} from 'DraftEditorCommand';\nimport type {DraftHandleValue} from 'DraftHandleValue';\nimport type {DraftInlineStyle} from 'DraftInlineStyle';\nimport type {DraftTextAlignment} from 'DraftTextAlignment';\nimport type EditorState from 'EditorState';\nimport type SelectionState from 'SelectionState';\nimport type {BidiDirection} from 'UnicodeBidiDirection';\n\nexport type DraftEditorProps = {\n  /**\n   * The two most critical props are `editorState` and `onChange`.\n   *\n   * The `editorState` prop defines the entire state of the editor, while the\n   * `onChange` prop is the method in which all state changes are propagated\n   * upward to higher-level components.\n   *\n   * These props are analogous to `value` and `onChange` in controlled React\n   * text inputs.\n   */\n  editorState: EditorState,\n  onChange: (editorState: EditorState) => void,\n  // specify editorKey when rendering serverside. If you do not set this prop\n  // react will complain that there is a server/client mismatch because Draft\n  // will generate a random editorKey when rendering in each context. The key\n  // is used to figure out if content is being pasted within a draft block to\n  // better apply formatting and styles.  If two editors share the same key &\n  // `stripPastedStyles` is false, draft will assume both editors share their\n  // styling and formatting when re-applying styles.\n  editorKey?: string,\n  placeholder?: string,\n  placeholderAriaHidden?: boolean,\n  placeholderClassName?: string,\n  // Specify whether text alignment should be forced in a direction\n  // regardless of input characters.\n  textAlignment?: DraftTextAlignment,\n  // Specify whether text directionality should be forced in a direction\n  // regardless of input characters.\n  textDirectionality?: BidiDirection,\n  // For a given `ContentBlock` object, return an object that specifies\n  // a custom block component and/or props. If no object is returned,\n  // the default `DraftEditorBlock` is used.\n  blockRendererFn: (block: BlockNodeRecord) => ?Object,\n  // Function that returns a cx map corresponding to block-level styles.\n  blockStyleFn: (block: BlockNodeRecord) => string,\n  // If supplied, a ref which will be passed to the contenteditable.\n  // Currently, only object refs are supported.\n  editorRef?: ?({current: null | HTMLElement} | ((HTMLElement | null) => void)),\n  // A function that accepts a synthetic key event and returns\n  // the matching DraftEditorCommand constant, or a custom string,\n  // or null if no command should be invoked.\n  keyBindingFn: (e: SyntheticKeyboardEvent<>) => ?string,\n  // Set whether the editor should prevent scrolling into view on mount\n  // if it happens offscreen. By default, `false` to match the native behavior.\n  preventScroll?: boolean,\n  // Set whether the `DraftEditor` component should be editable. Useful for\n  // temporarily disabling edit behavior or allowing `DraftEditor` rendering\n  // to be used for consumption purposes.\n  readOnly: boolean,\n  // Note: spellcheck is always disabled for IE. If enabled in Safari, OSX\n  // autocorrect is enabled as well.\n  spellCheck: boolean,\n  // Set whether to remove all style information from pasted content. If your\n  // use case should not have any block or inline styles, it is recommended\n  // that you set this to `true`.\n  stripPastedStyles: boolean,\n  formatPastedText?: (\n    text: string,\n    html: ?string,\n  ) => {text: string, html: ?string},\n  tabIndex?: number,\n  // exposed especially to help improve mobile web behaviors\n  autoCapitalize?: string,\n  autoComplete?: string,\n  autoCorrect?: string,\n  ariaActiveDescendantID?: string,\n  ariaAutoComplete?: string,\n  ariaControls?: string,\n  /**\n   * aria-describedby attribute. should point to the id of a descriptive\n   * element. The substring, \"{{editor_id_placeholder}}\" will be replaced with\n   * the DOM id of the placeholder element if it exists.\n   * @default \"{{editor_id_placeholder}}\"\n   */\n  ariaDescribedBy?: string,\n  ariaExpanded?: boolean,\n  ariaLabel?: string,\n  ariaLabelledBy?: string,\n  ariaMultiline?: boolean,\n  ariaOwneeID?: string,\n  /**\n   * aria-required attribute. Boolean value that indicates that whether an\n   * element is required to submit (true) or not. While HTML5 does have a\n   * `required` attribute now, some browsers don't support it yet and it only\n   * applies to input elements in either case.\n   */\n  ariaRequired?: string,\n  webDriverTestID?: string,\n  /**\n   * Cancelable event handlers, handled from the top level down. A handler\n   * that returns `handled` will be the last handler to execute for that event.\n   */\n\n  // Useful for managing special behavior for pressing the `Return` key. E.g.\n  // removing the style from an empty list item.\n  handleReturn?: (\n    e: SyntheticKeyboardEvent<>,\n    editorState: EditorState,\n  ) => DraftHandleValue,\n  // Map a key command string provided by your key binding function to a\n  // specified behavior.\n  handleKeyCommand?: (\n    command: DraftEditorCommand | string,\n    editorState: EditorState,\n    eventTimeStamp: number,\n  ) => DraftHandleValue,\n  // Handle intended text insertion before the insertion occurs. This may be\n  // useful in cases where the user has entered characters that you would like\n  // to trigger some special behavior. E.g. immediately converting `:)` to an\n  // emoji Unicode character, or replacing ASCII quote characters with smart\n  // quotes.\n  handleBeforeInput?: (\n    chars: string,\n    editorState: EditorState,\n    eventTimeStamp: number,\n  ) => DraftHandleValue,\n  handlePastedText?: (\n    text: string,\n    html?: string,\n    editorState: EditorState,\n    isInternalPaste: boolean,\n  ) => DraftHandleValue,\n  handlePastedFiles?: (files: Array<Blob>) => DraftHandleValue,\n  // Handle dropped files\n  handleDroppedFiles?: (\n    selection: SelectionState,\n    files: Array<Blob>,\n  ) => DraftHandleValue,\n  // Handle other drops to prevent default text movement/insertion behaviour\n  handleDrop?: (\n    selection: SelectionState,\n    dataTransfer: Object,\n    isInternal: DraftDragType,\n  ) => DraftHandleValue,\n  /**\n   * Deprecated event triggers.\n   */\n  onEscape?: (e: SyntheticKeyboardEvent<>) => void,\n  onTab?: (e: SyntheticKeyboardEvent<>) => void,\n  onUpArrow?: (e: SyntheticKeyboardEvent<>) => void,\n  onRightArrow?: (e: SyntheticKeyboardEvent<>) => void,\n  onDownArrow?: (e: SyntheticKeyboardEvent<>) => void,\n  onLeftArrow?: (e: SyntheticKeyboardEvent<>) => void,\n  onBlur?: (e: SyntheticEvent<>) => void,\n  onFocus?: (e: SyntheticEvent<>) => void,\n  // Provide a map of inline style names corresponding to CSS style objects\n  // that will be rendered for matching ranges.\n  customStyleMap?: Object,\n  // Provide a function that will construct CSS style objects given inline\n  // style names.\n  customStyleFn?: (style: DraftInlineStyle, block: BlockNodeRecord) => ?Object,\n  // Provide a map of block rendering configurations. Each block type maps to\n  // an element tag and an optional react element wrapper. This configuration\n  // is used for both rendering and paste processing.\n  blockRenderMap: DraftBlockRenderMap,\n  // When the Editor loses focus (blurs) text selections are cleared\n  // by default to mimic <textarea> behaviour, however in some situations\n  // users may wish to preserve native behaviour.\n  preserveSelectionOnBlur?: boolean,\n  // Overrides for cut, copy & paste, which can be used to implement custom\n  // behavior like entity cut/copy/paste (see PR #1784).\"\n  onPaste?: (DraftEditor, SyntheticClipboardEvent<>) => void | Promise<void>,\n  onCut?: (DraftEditor, SyntheticClipboardEvent<>) => void,\n  onCopy?: (DraftEditor, SyntheticClipboardEvent<>) => void,\n  contentClassName?: string,\n  ...\n};\n\nexport type DraftEditorDefaultProps = {\n  ariaDescribedBy: string,\n  blockRenderMap: DraftBlockRenderMap,\n  blockRendererFn: (block: BlockNodeRecord) => ?Object,\n  blockStyleFn: (block: BlockNodeRecord) => string,\n  keyBindingFn: (e: SyntheticKeyboardEvent<>) => ?string,\n  readOnly: boolean,\n  spellCheck: boolean,\n  stripPastedStyles: boolean,\n  ...\n};\n"
  },
  {
    "path": "src/component/base/DraftScrollPosition.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nexport type DraftScrollPosition = $ReadOnly<{\n  x: number,\n  y: number,\n}>;\n"
  },
  {
    "path": "src/component/base/DraftTextAlignment.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nexport type DraftTextAlignment = 'left' | 'center' | 'right';\n"
  },
  {
    "path": "src/component/base/__tests__/DraftEditor.react-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\njest.mock('generateRandomKey');\n\nconst DraftEditor = require('DraftEditor.react');\nconst EditorState = require('EditorState');\n\nconst React = require('react');\n// $FlowFixMe[cannot-resolve-module]\nconst ReactShallowRenderer = require('react-test-renderer/shallow');\n\nlet shallow;\nlet editorState;\n\nbeforeEach(() => {\n  shallow = new ReactShallowRenderer();\n  editorState = EditorState.createEmpty();\n});\n\ntest('must has generated editorKey', () => {\n  shallow.render(<DraftEditor editorState={editorState} onChange={() => {}} />);\n\n  // internally at Facebook we use a newer version of the shallowRenderer\n  // which has a different level of wrapping of the '_instance'\n  // long term we should rewrite this test to not depend on private\n  // properties\n  const getEditorKey =\n    shallow._instance.getEditorKey || shallow._instance._instance.getEditorKey;\n  expect(getEditorKey()).toMatchSnapshot();\n});\n\ntest('must has editorKey same as props', () => {\n  shallow.render(\n    <DraftEditor\n      editorState={editorState}\n      onChange={() => {}}\n      editorKey=\"hash\"\n    />,\n  );\n\n  // internally at Facebook we use a newer version of the shallowRenderer\n  // which has a different level of wrapping of the '_instance'\n  // long term we should rewrite this test to not depend on private\n  // properties\n  const getEditorKey =\n    shallow._instance.getEditorKey || shallow._instance._instance.getEditorKey;\n  expect(getEditorKey()).toMatchSnapshot();\n});\n\ndescribe('ariaDescribedBy', () => {\n  function getProps(elem: React.Node) {\n    const r = shallow.render(elem);\n    const ec = r.props.children[1].props.children;\n    return ec.props;\n  }\n\n  describe('without placeholder', () => {\n    test('undefined by default', () => {\n      const props = getProps(\n        <DraftEditor editorState={editorState} onChange={() => {}} />,\n      );\n      expect(props).toHaveProperty('aria-describedby', undefined);\n    });\n\n    test('can be set to something arbitrary', () => {\n      const props = getProps(\n        <DraftEditor\n          editorState={editorState}\n          onChange={() => {}}\n          ariaDescribedBy=\"abc\"\n        />,\n      );\n      expect(props).toHaveProperty('aria-describedby', 'abc');\n    });\n\n    test('can use special token', () => {\n      const props = getProps(\n        <DraftEditor\n          editorState={editorState}\n          onChange={() => {}}\n          ariaDescribedBy=\"abc {{editor_id_placeholder}} xyz\"\n        />,\n      );\n      expect(props).toHaveProperty('aria-describedby', 'abc  xyz');\n    });\n  });\n\n  describe('with placeholder', () => {\n    test('has placeholder id by default', () => {\n      const props = getProps(\n        <DraftEditor\n          editorState={editorState}\n          onChange={() => {}}\n          editorKey=\"X\"\n          placeholder=\"place\"\n        />,\n      );\n      expect(props).toHaveProperty('aria-describedby', 'placeholder-X');\n    });\n\n    test('can be set to something arbitrary', () => {\n      const props = getProps(\n        <DraftEditor\n          editorState={editorState}\n          onChange={() => {}}\n          editorKey=\"X\"\n          placeholder=\"place\"\n          ariaDescribedBy=\"abc\"\n        />,\n      );\n      expect(props).toHaveProperty('aria-describedby', 'abc');\n    });\n\n    test('can use special token', () => {\n      const props = getProps(\n        <DraftEditor\n          editorState={editorState}\n          onChange={() => {}}\n          editorKey=\"X\"\n          placeholder=\"place\"\n          ariaDescribedBy=\"abc {{editor_id_placeholder}} xyz\"\n        />,\n      );\n      expect(props).toHaveProperty('aria-describedby', 'abc placeholder-X xyz');\n    });\n  });\n});\n"
  },
  {
    "path": "src/component/base/__tests__/__snapshots__/DraftEditor.react-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must has editorKey same as props 1`] = `\"hash\"`;\n\nexports[`must has generated editorKey 1`] = `\"key1\"`;\n"
  },
  {
    "path": "src/component/contents/DraftEditorBlock.react.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type ContentState from 'ContentState';\nimport type {DraftDecoratorComponentProps} from 'DraftDecorator';\nimport type {DraftDecoratorType} from 'DraftDecoratorType';\nimport type {DraftInlineStyle} from 'DraftInlineStyle';\nimport type SelectionState from 'SelectionState';\nimport type {BidiDirection} from 'UnicodeBidiDirection';\nimport type {List} from 'immutable';\n\nconst DraftEditorLeaf = require('DraftEditorLeaf.react');\nconst DraftOffsetKey = require('DraftOffsetKey');\nconst Scroll = require('Scroll');\nconst Style = require('Style');\nconst UnicodeBidi = require('UnicodeBidi');\nconst UnicodeBidiDirection = require('UnicodeBidiDirection');\n\nconst cx = require('cx');\nconst getElementPosition = require('getElementPosition');\nconst getScrollPosition = require('getScrollPosition');\nconst getViewportDimensions = require('getViewportDimensions');\nconst invariant = require('invariant');\nconst isHTMLElement = require('isHTMLElement');\nconst nullthrows = require('nullthrows');\nconst React = require('react');\n\nconst SCROLL_BUFFER = 10;\n\ntype Props = {\n  block: BlockNodeRecord,\n  blockProps?: Object,\n  blockStyleFn: (block: BlockNodeRecord) => string,\n  contentState: ContentState,\n  customStyleFn?: (style: DraftInlineStyle, block: BlockNodeRecord) => ?Object,\n  customStyleMap: Object,\n  decorator: ?DraftDecoratorType,\n  direction: BidiDirection,\n  forceSelection: boolean,\n  offsetKey: string,\n  preventScroll?: boolean,\n  selection: SelectionState,\n  startIndent?: boolean,\n  tree: List<any>,\n  ...\n};\n\n/**\n * Return whether a block overlaps with either edge of the `SelectionState`.\n */\nconst isBlockOnSelectionEdge = (\n  selection: SelectionState,\n  key: string,\n): boolean => {\n  return selection.getAnchorKey() === key || selection.getFocusKey() === key;\n};\n\n/**\n * The default block renderer for a `DraftEditor` component.\n *\n * A `DraftEditorBlock` is able to render a given `ContentBlock` to its\n * appropriate decorator and inline style components.\n */\nclass DraftEditorBlock extends React.Component<Props> {\n  _node: ?HTMLDivElement;\n\n  shouldComponentUpdate(nextProps: Props): boolean {\n    return (\n      this.props.block !== nextProps.block ||\n      this.props.tree !== nextProps.tree ||\n      this.props.direction !== nextProps.direction ||\n      (isBlockOnSelectionEdge(nextProps.selection, nextProps.block.getKey()) &&\n        nextProps.forceSelection)\n    );\n  }\n\n  /**\n   * When a block is mounted and overlaps the selection state, we need to make\n   * sure that the cursor is visible to match native behavior. This may not\n   * be the case if the user has pressed `RETURN` or pasted some content, since\n   * programmatically creating these new blocks and setting the DOM selection\n   * will miss out on the browser natively scrolling to that position.\n   *\n   * To replicate native behavior, if the block overlaps the selection state\n   * on mount, force the scroll position. Check the scroll state of the scroll\n   * parent, and adjust it to align the entire block to the bottom of the\n   * scroll parent.\n   */\n  componentDidMount(): void {\n    if (this.props.preventScroll) {\n      return;\n    }\n    const selection = this.props.selection;\n    const endKey = selection.getEndKey();\n    if (!selection.getHasFocus() || endKey !== this.props.block.getKey()) {\n      return;\n    }\n\n    const blockNode = this._node;\n    if (blockNode == null) {\n      return;\n    }\n    const scrollParent = Style.getScrollParent(blockNode);\n    const scrollPosition = getScrollPosition(scrollParent);\n    let scrollDelta;\n\n    if (scrollParent === window) {\n      const nodePosition = getElementPosition(blockNode);\n      const nodeBottom = nodePosition.y + nodePosition.height;\n      const viewportHeight = getViewportDimensions().height;\n      scrollDelta = nodeBottom - viewportHeight;\n      if (scrollDelta > 0) {\n        window.scrollTo(\n          scrollPosition.x,\n          scrollPosition.y + scrollDelta + SCROLL_BUFFER,\n        );\n      }\n    } else {\n      invariant(isHTMLElement(blockNode), 'blockNode is not an HTMLElement');\n      const blockBottom = blockNode.offsetHeight + blockNode.offsetTop;\n      const pOffset = scrollParent.offsetTop + scrollParent.offsetHeight;\n      const scrollBottom = pOffset + scrollPosition.y;\n\n      scrollDelta = blockBottom - scrollBottom;\n      if (scrollDelta > 0) {\n        Scroll.setTop(\n          scrollParent,\n          Scroll.getTop(scrollParent) + scrollDelta + SCROLL_BUFFER,\n        );\n      }\n    }\n  }\n\n  _renderChildren(): Array<React.Node> {\n    const block = this.props.block;\n    const blockKey = block.getKey();\n    const text = block.getText();\n    const lastLeafSet = this.props.tree.size - 1;\n    const hasSelection = isBlockOnSelectionEdge(this.props.selection, blockKey);\n\n    return this.props.tree\n      .map((leafSet, ii) => {\n        const leavesForLeafSet = leafSet.get('leaves');\n        // T44088704\n        if (leavesForLeafSet.size === 0) {\n          return null;\n        }\n        const lastLeaf = leavesForLeafSet.size - 1;\n        const leaves = leavesForLeafSet\n          .map((leaf, jj) => {\n            const offsetKey = DraftOffsetKey.encode(blockKey, ii, jj);\n            const start = leaf.get('start');\n            const end = leaf.get('end');\n            return (\n              <DraftEditorLeaf\n                key={offsetKey}\n                offsetKey={offsetKey}\n                block={block}\n                start={start}\n                selection={hasSelection ? this.props.selection : null}\n                forceSelection={this.props.forceSelection}\n                text={text.slice(start, end)}\n                styleSet={block.getInlineStyleAt(start)}\n                customStyleMap={this.props.customStyleMap}\n                customStyleFn={this.props.customStyleFn}\n                isLast={ii === lastLeafSet && jj === lastLeaf}\n              />\n            );\n          })\n          .toArray();\n\n        const decoratorKey = leafSet.get('decoratorKey');\n        if (decoratorKey == null) {\n          return leaves;\n        }\n\n        if (!this.props.decorator) {\n          return leaves;\n        }\n\n        const decorator = nullthrows(this.props.decorator);\n\n        const DecoratorComponent = decorator.getComponentForKey(decoratorKey);\n        if (!DecoratorComponent) {\n          return leaves;\n        }\n\n        const decoratorProps = decorator.getPropsForKey(decoratorKey);\n        const decoratorOffsetKey = DraftOffsetKey.encode(blockKey, ii, 0);\n        const start = leavesForLeafSet.first().get('start');\n        const end = leavesForLeafSet.last().get('end');\n        const decoratedText = text.slice(start, end);\n        const entityKey = block.getEntityAt(leafSet.get('start'));\n\n        // Resetting dir to the same value on a child node makes Chrome/Firefox\n        // confused on cursor movement. See http://jsfiddle.net/d157kLck/3/\n        const dir = UnicodeBidiDirection.getHTMLDirIfDifferent(\n          UnicodeBidi.getDirection(decoratedText),\n          this.props.direction,\n        );\n\n        const commonProps: DraftDecoratorComponentProps = {\n          contentState: this.props.contentState,\n          decoratedText,\n          dir,\n          start,\n          end,\n          blockKey,\n          entityKey,\n          offsetKey: decoratorOffsetKey,\n        };\n\n        return (\n          <DecoratorComponent\n            {...decoratorProps}\n            {...commonProps}\n            key={decoratorOffsetKey}>\n            {leaves}\n          </DecoratorComponent>\n        );\n      })\n      .toArray();\n  }\n\n  render(): React.Node {\n    const {direction, offsetKey} = this.props;\n    const className = cx({\n      'public/DraftStyleDefault/block': true,\n      'public/DraftStyleDefault/ltr': direction === 'LTR',\n      'public/DraftStyleDefault/rtl': direction === 'RTL',\n    });\n\n    return (\n      <div\n        data-offset-key={offsetKey}\n        className={className}\n        ref={ref => (this._node = ref)}>\n        {this._renderChildren()}\n      </div>\n    );\n  }\n}\n\nmodule.exports = DraftEditorBlock;\n"
  },
  {
    "path": "src/component/contents/DraftEditorContents-core.react.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type {DraftBlockRenderMap} from 'DraftBlockRenderMap';\nimport type {DraftInlineStyle} from 'DraftInlineStyle';\nimport type EditorState from 'EditorState';\nimport type {BidiDirection} from 'UnicodeBidiDirection';\n\nconst DraftEditorBlock = require('DraftEditorBlock.react');\nconst DraftOffsetKey = require('DraftOffsetKey');\n\nconst cx = require('cx');\nconst joinClasses: (\n  className?: ?string,\n  ...classes: Array<?string>\n) => string = require('joinClasses');\nconst nullthrows = require('nullthrows');\nconst React = require('react');\n\ntype Props = {\n  blockRenderMap: DraftBlockRenderMap,\n  blockRendererFn: (block: BlockNodeRecord) => ?Object,\n  blockStyleFn: (block: BlockNodeRecord) => string,\n  customStyleFn?: (style: DraftInlineStyle, block: BlockNodeRecord) => ?Object,\n  customStyleMap?: Object,\n  editorKey?: string,\n  editorState: EditorState,\n  preventScroll?: boolean,\n  textDirectionality?: BidiDirection,\n  ...\n};\n\n/**\n * Provide default styling for list items. This way, lists will be styled with\n * proper counters and indentation even if the caller does not specify\n * their own styling at all. If more than five levels of nesting are needed,\n * the necessary CSS classes can be provided via `blockStyleFn` configuration.\n */\nconst getListItemClasses = (\n  type: string,\n  depth: number,\n  shouldResetCount: boolean,\n  direction: BidiDirection,\n): string => {\n  return cx({\n    'public/DraftStyleDefault/unorderedListItem':\n      type === 'unordered-list-item',\n    'public/DraftStyleDefault/orderedListItem': type === 'ordered-list-item',\n    'public/DraftStyleDefault/reset': shouldResetCount,\n    'public/DraftStyleDefault/depth0': depth === 0,\n    'public/DraftStyleDefault/depth1': depth === 1,\n    'public/DraftStyleDefault/depth2': depth === 2,\n    'public/DraftStyleDefault/depth3': depth === 3,\n    'public/DraftStyleDefault/depth4': depth >= 4,\n    'public/DraftStyleDefault/listLTR': direction === 'LTR',\n    'public/DraftStyleDefault/listRTL': direction === 'RTL',\n  });\n};\n\n/**\n * `DraftEditorContents` is the container component for all block components\n * rendered for a `DraftEditor`. It is optimized to aggressively avoid\n * re-rendering blocks whenever possible.\n *\n * This component is separate from `DraftEditor` because certain props\n * (for instance, ARIA props) must be allowed to update without affecting\n * the contents of the editor.\n */\nclass DraftEditorContents extends React.Component<Props> {\n  shouldComponentUpdate(nextProps: Props): boolean {\n    const prevEditorState = this.props.editorState;\n    const nextEditorState = nextProps.editorState;\n\n    const prevDirectionMap = prevEditorState.getDirectionMap();\n    const nextDirectionMap = nextEditorState.getDirectionMap();\n\n    // Text direction has changed for one or more blocks. We must re-render.\n    if (prevDirectionMap !== nextDirectionMap) {\n      return true;\n    }\n\n    const didHaveFocus = prevEditorState.getSelection().getHasFocus();\n    const nowHasFocus = nextEditorState.getSelection().getHasFocus();\n\n    if (didHaveFocus !== nowHasFocus) {\n      return true;\n    }\n\n    const nextNativeContent = nextEditorState.getNativelyRenderedContent();\n\n    const wasComposing = prevEditorState.isInCompositionMode();\n    const nowComposing = nextEditorState.isInCompositionMode();\n\n    // If the state is unchanged or we're currently rendering a natively\n    // rendered state, there's nothing new to be done.\n    if (\n      prevEditorState === nextEditorState ||\n      (nextNativeContent !== null &&\n        nextEditorState.getCurrentContent() === nextNativeContent) ||\n      (wasComposing && nowComposing)\n    ) {\n      return false;\n    }\n\n    const prevContent = prevEditorState.getCurrentContent();\n    const nextContent = nextEditorState.getCurrentContent();\n    const prevDecorator = prevEditorState.getDecorator();\n    const nextDecorator = nextEditorState.getDecorator();\n    return (\n      wasComposing !== nowComposing ||\n      prevContent !== nextContent ||\n      prevDecorator !== nextDecorator ||\n      nextEditorState.mustForceSelection()\n    );\n  }\n\n  render(): React.Node {\n    const {\n      blockRenderMap,\n      blockRendererFn,\n      blockStyleFn,\n      customStyleMap,\n      customStyleFn,\n      editorState,\n      editorKey,\n      preventScroll,\n      textDirectionality,\n    } = this.props;\n\n    const content = editorState.getCurrentContent();\n    const selection = editorState.getSelection();\n    const forceSelection = editorState.mustForceSelection();\n    const decorator = editorState.getDecorator();\n    const directionMap = nullthrows(editorState.getDirectionMap());\n\n    const blocksAsArray = content.getBlocksAsArray();\n    const processedBlocks = [];\n    const alreadyEncounteredDepth = new Set<number>();\n    let currentDepth = null;\n    let lastWrapperTemplate = null;\n\n    for (let ii = 0; ii < blocksAsArray.length; ii++) {\n      const block = blocksAsArray[ii];\n      const key = block.getKey();\n      const blockType = block.getType();\n\n      const customRenderer = blockRendererFn(block);\n      let CustomComponent, customProps, customEditable;\n      if (customRenderer) {\n        CustomComponent = customRenderer.component;\n        customProps = customRenderer.props;\n        customEditable = customRenderer.editable;\n      }\n\n      const direction = textDirectionality\n        ? textDirectionality\n        : directionMap.get(key);\n      const offsetKey = DraftOffsetKey.encode(key, 0, 0);\n      const componentProps = {\n        contentState: content,\n        block,\n        blockProps: customProps,\n        blockStyleFn,\n        customStyleMap,\n        customStyleFn,\n        decorator,\n        direction,\n        forceSelection,\n        offsetKey,\n        preventScroll,\n        selection,\n        tree: editorState.getBlockTree(key),\n      };\n\n      const configForType =\n        blockRenderMap.get(blockType) || blockRenderMap.get('unstyled');\n      const wrapperTemplate = configForType.wrapper;\n\n      const Element =\n        configForType.element || blockRenderMap.get('unstyled').element;\n\n      const depth = block.getDepth();\n      let className = '';\n      if (blockStyleFn) {\n        className = blockStyleFn(block);\n      }\n\n      // List items are special snowflakes, since we handle nesting and\n      // counters manually.\n      if (Element === 'li') {\n        const shouldResetCount =\n          lastWrapperTemplate !== wrapperTemplate ||\n          currentDepth === null ||\n          depth > currentDepth ||\n          (depth < currentDepth && !alreadyEncounteredDepth.has(depth));\n        className = joinClasses(\n          className,\n          getListItemClasses(blockType, depth, shouldResetCount, direction),\n        );\n      }\n\n      alreadyEncounteredDepth.add(depth);\n\n      const Component = CustomComponent || DraftEditorBlock;\n      let childProps = {\n        className,\n        'data-block': true,\n        'data-editor': editorKey,\n        'data-offset-key': offsetKey,\n        key,\n      };\n      if (customEditable !== undefined) {\n        childProps = {\n          ...childProps,\n          contentEditable: customEditable,\n          suppressContentEditableWarning: true,\n        };\n      }\n\n      const child = React.createElement(\n        Element,\n        childProps,\n        <Component {...componentProps} key={key} />,\n      );\n\n      processedBlocks.push({\n        block: child,\n        wrapperTemplate,\n        key,\n        offsetKey,\n      });\n\n      if (wrapperTemplate) {\n        currentDepth = block.getDepth();\n      } else {\n        currentDepth = null;\n      }\n      lastWrapperTemplate = wrapperTemplate;\n    }\n\n    // Group contiguous runs of blocks that have the same wrapperTemplate\n    const outputBlocks = [];\n    for (let ii = 0; ii < processedBlocks.length; ) {\n      const info: any = processedBlocks[ii];\n      if (info.wrapperTemplate) {\n        const blocks = [];\n        do {\n          blocks.push(processedBlocks[ii].block);\n          ii++;\n        } while (\n          ii < processedBlocks.length &&\n          processedBlocks[ii].wrapperTemplate === info.wrapperTemplate\n        );\n        const wrapperElement = React.cloneElement(\n          info.wrapperTemplate,\n          {\n            key: info.key + '-wrap',\n            'data-offset-key': info.offsetKey,\n          },\n          blocks,\n        );\n        outputBlocks.push(wrapperElement);\n      } else {\n        outputBlocks.push(info.block);\n        ii++;\n      }\n    }\n\n    return <div data-contents=\"true\">{outputBlocks}</div>;\n  }\n}\n\nmodule.exports = DraftEditorContents;\n"
  },
  {
    "path": "src/component/contents/DraftEditorLeaf.react.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type {DraftInlineStyle} from 'DraftInlineStyle';\nimport type SelectionState from 'SelectionState';\n\nconst DraftEditorTextNode = require('DraftEditorTextNode.react');\n\nconst invariant = require('invariant');\nconst isHTMLBRElement = require('isHTMLBRElement');\nconst React = require('react');\nconst setDraftEditorSelection =\n  require('setDraftEditorSelection').setDraftEditorSelection;\n\ntype CSSStyleObject = {[property: string]: string | number, ...};\n\ntype CustomStyleMap = {[name: string]: CSSStyleObject, ...};\ntype CustomStyleFn = (\n  style: DraftInlineStyle,\n  block: BlockNodeRecord,\n) => ?CSSStyleObject;\n\ntype Props = {\n  // The block that contains this leaf.\n  block: BlockNodeRecord,\n  // Mapping of style names to CSS declarations.\n  customStyleMap: CustomStyleMap,\n  // Function that maps style names to CSS style objects.\n  customStyleFn?: CustomStyleFn,\n  // Whether to force the DOM selection after render.\n  forceSelection: boolean,\n  // Whether this leaf is the last in its block. Used for a DOM hack.\n  isLast: boolean,\n  offsetKey: string,\n  // The current `SelectionState`, used to represent a selection range in the\n  // editor\n  selection: ?SelectionState,\n  // The offset of this string within its block.\n  start: number,\n  // The set of style(s) names to apply to the node.\n  styleSet: DraftInlineStyle,\n  // The full text to be rendered within this node.\n  text: string,\n  ...\n};\n\n/**\n * All leaf nodes in the editor are spans with single text nodes. Leaf\n * elements are styled based on the merging of an optional custom style map\n * and a default style map.\n *\n * `DraftEditorLeaf` also provides a wrapper for calling into the imperative\n * DOM Selection API. In this way, top-level components can declaratively\n * maintain the selection state.\n */\nclass DraftEditorLeaf extends React.Component<Props> {\n  /**\n   * By making individual leaf instances aware of their context within\n   * the text of the editor, we can set our selection range more\n   * easily than we could in the non-React world.\n   *\n   * Note that this depends on our maintaining tight control over the\n   * DOM structure of the DraftEditor component. If leaves had multiple\n   * text nodes, this would be harder.\n   */\n\n  leaf: ?HTMLElement;\n\n  _setSelection(): void {\n    const {selection} = this.props;\n\n    // If selection state is irrelevant to the parent block, no-op.\n    if (selection == null || !selection.getHasFocus()) {\n      return;\n    }\n\n    const {block, start, text} = this.props;\n    const blockKey = block.getKey();\n    const end = start + text.length;\n    if (!selection.hasEdgeWithin(blockKey, start, end)) {\n      return;\n    }\n\n    // Determine the appropriate target node for selection. If the child\n    // is not a text node, it is a <br /> spacer. In this case, use the\n    // <span> itself as the selection target.\n    const node = this.leaf;\n    invariant(node, 'Missing node');\n    const child = node.firstChild;\n    invariant(child, 'Missing child');\n    let targetNode;\n\n    if (child.nodeType === Node.TEXT_NODE) {\n      targetNode = child;\n    } else if (isHTMLBRElement(child)) {\n      targetNode = node;\n    } else {\n      targetNode = child.firstChild;\n      invariant(targetNode, 'Missing targetNode');\n    }\n\n    setDraftEditorSelection(selection, targetNode, blockKey, start, end);\n  }\n\n  shouldComponentUpdate(nextProps: Props): boolean {\n    const leafNode = this.leaf;\n    invariant(leafNode, 'Missing leafNode');\n    const shouldUpdate =\n      leafNode.textContent !== nextProps.text ||\n      nextProps.styleSet !== this.props.styleSet ||\n      nextProps.forceSelection;\n    return shouldUpdate;\n  }\n\n  componentDidUpdate(): void {\n    this._setSelection();\n  }\n\n  componentDidMount(): void {\n    this._setSelection();\n  }\n\n  render(): React.Node {\n    const {block} = this.props;\n    let {text} = this.props;\n\n    // If the leaf is at the end of its block and ends in a soft newline, append\n    // an extra line feed character. Browsers collapse trailing newline\n    // characters, which leaves the cursor in the wrong place after a\n    // shift+enter. The extra character repairs this.\n    if (text.endsWith('\\n') && this.props.isLast) {\n      text += '\\n';\n    }\n\n    const {customStyleMap, customStyleFn, offsetKey, styleSet} = this.props;\n    let styleObj = styleSet.reduce((map, styleName) => {\n      const mergedStyles: {textDecoration?: string, ...} = {};\n      const style = customStyleMap[styleName];\n\n      if (style !== undefined && map.textDecoration !== style.textDecoration) {\n        // .trim() is necessary for IE9/10/11 and Edge\n        mergedStyles.textDecoration = [map.textDecoration, style.textDecoration]\n          .join(' ')\n          .trim();\n      }\n\n      return Object.assign(map, style, mergedStyles);\n    }, {});\n\n    if (customStyleFn) {\n      const newStyles = customStyleFn(styleSet, block);\n      styleObj = Object.assign(styleObj, newStyles);\n    }\n\n    return (\n      <span\n        data-offset-key={offsetKey}\n        ref={ref => (this.leaf = ref)}\n        style={styleObj}>\n        <DraftEditorTextNode>{text}</DraftEditorTextNode>\n      </span>\n    );\n  }\n}\n\nmodule.exports = DraftEditorLeaf;\n"
  },
  {
    "path": "src/component/contents/DraftEditorTextNode.react.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst UserAgent = require('UserAgent');\n\nconst invariant = require('invariant');\nconst isElement = require('isElement');\nconst React = require('react');\n\n// In IE, spans with <br> tags render as two newlines. By rendering a span\n// with only a newline character, we can be sure to render a single line.\nconst useNewlineChar = UserAgent.isBrowser('IE <= 11');\n\n/**\n * Check whether the node should be considered a newline.\n */\nfunction isNewline(node: Element): boolean {\n  return useNewlineChar ? node.textContent === '\\n' : node.tagName === 'BR';\n}\n\n/**\n * Placeholder elements for empty text content.\n *\n * What is this `data-text` attribute, anyway? It turns out that we need to\n * put an attribute on the lowest-level text node in order to preserve correct\n * spellcheck handling. If the <span> is naked, Chrome and Safari may do\n * bizarre things to do the DOM -- split text nodes, create extra spans, etc.\n * If the <span> has an attribute, this appears not to happen.\n * See http://jsfiddle.net/9khdavod/ for the failure case, and\n * http://jsfiddle.net/7pg143f7/ for the fixed case.\n */\nconst NEWLINE_A = (\n  ref: (\n    ref:\n      | null\n      | React$ElementRef<$TEMPORARY$string<'br'>>\n      | React$ElementRef<$TEMPORARY$string<'span'>>,\n  ) => null | HTMLSpanElement | HTMLBRElement,\n) =>\n  useNewlineChar ? (\n    <span key=\"A\" data-text=\"true\" ref={ref}>\n      {'\\n'}\n    </span>\n  ) : (\n    <br key=\"A\" data-text=\"true\" ref={ref} />\n  );\n\nconst NEWLINE_B = (\n  ref: (\n    ref:\n      | null\n      | React$ElementRef<$TEMPORARY$string<'br'>>\n      | React$ElementRef<$TEMPORARY$string<'span'>>,\n  ) => null | HTMLSpanElement | HTMLBRElement,\n) =>\n  useNewlineChar ? (\n    <span key=\"B\" data-text=\"true\" ref={ref}>\n      {'\\n'}\n    </span>\n  ) : (\n    <br key=\"B\" data-text=\"true\" ref={ref} />\n  );\n\ntype Props = {children: string, ...};\n\n/**\n * The lowest-level component in a `DraftEditor`, the text node component\n * replaces the default React text node implementation. This allows us to\n * perform custom handling of newline behavior and avoid re-rendering text\n * nodes with DOM state that already matches the expectations of our immutable\n * editor state.\n */\nclass DraftEditorTextNode extends React.Component<Props> {\n  _forceFlag: boolean;\n  _node: ?(HTMLSpanElement | HTMLBRElement);\n\n  constructor(props: Props) {\n    super(props);\n    // By flipping this flag, we also keep flipping keys which forces\n    // React to remount this node every time it rerenders.\n    this._forceFlag = false;\n  }\n\n  shouldComponentUpdate(nextProps: Props): boolean {\n    const node = this._node;\n    const shouldBeNewline = nextProps.children === '';\n\n    invariant(isElement(node), 'node is not an Element');\n    const elementNode: Element = (node: any);\n    if (shouldBeNewline) {\n      return !isNewline(elementNode);\n    }\n    return elementNode.textContent !== nextProps.children;\n  }\n\n  componentDidMount(): void {\n    this._forceFlag = !this._forceFlag;\n  }\n\n  componentDidUpdate(): void {\n    this._forceFlag = !this._forceFlag;\n  }\n\n  render(): React.Node {\n    if (this.props.children === '') {\n      return this._forceFlag\n        ? NEWLINE_A(ref => (this._node = ref))\n        : NEWLINE_B(ref => (this._node = ref));\n    }\n    return (\n      <span\n        key={this._forceFlag ? 'A' : 'B'}\n        data-text=\"true\"\n        ref={ref => (this._node = ref)}>\n        {this.props.children}\n      </span>\n    );\n  }\n}\n\nmodule.exports = DraftEditorTextNode;\n"
  },
  {
    "path": "src/component/contents/__tests__/DraftEditorBlock.react-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\njest\n  .mock('Style')\n  .mock('getElementPosition')\n  .mock('getScrollPosition')\n  .mock('getViewportDimensions');\n\nconst BlockTree = require('BlockTree');\nconst CharacterMetadata = require('CharacterMetadata');\nconst ContentBlock = require('ContentBlock');\nconst ContentState = require('ContentState');\nconst DraftEditorBlock = require('DraftEditorBlock.react');\nconst DraftEditorLeaf = require('DraftEditorLeaf.react');\nconst ReactDOM = require('ReactDOM');\nconst SampleDraftInlineStyle = require('SampleDraftInlineStyle');\nconst SelectionState = require('SelectionState');\nconst Style = require('Style');\nconst UnicodeBidiDirection = require('UnicodeBidiDirection');\n\nconst getElementPosition = require('getElementPosition');\nconst getScrollPosition = require('getScrollPosition');\nconst getViewportDimensions = require('getViewportDimensions');\nconst Immutable = require('immutable');\nconst React = require('react');\nconst ReactTestRenderer = require('react-test-renderer');\n\nconst {BOLD, NONE, ITALIC} = SampleDraftInlineStyle;\nconst mockGetDecorations = jest.fn();\nclass DecoratorSpan extends React.Component {\n  render() {\n    return <span>{this.props.children}</span>;\n  }\n}\n// Define a class to satisfy typechecks.\nclass Decorator {\n  getDecorations() {\n    return mockGetDecorations();\n  }\n  getComponentForKey() {\n    return DecoratorSpan;\n  }\n  getPropsForKey() {\n    return {};\n  }\n}\nconst mockLeafRender = jest.fn(() => <span />);\nclass MockEditorLeaf extends React.Component {\n  render() {\n    return mockLeafRender();\n  }\n}\njest.setMock('DraftEditorLeaf.react', MockEditorLeaf);\nStyle.getScrollParent.mockReturnValue(window);\nwindow.scrollTo = jest.fn();\ngetElementPosition.mockReturnValue({\n  x: 0,\n  y: 600,\n  width: 500,\n  height: 16,\n});\ngetScrollPosition.mockReturnValue({x: 0, y: 0});\ngetViewportDimensions.mockReturnValue({width: 1200, height: 800});\n\nconst returnEmptyString = () => {\n  return '';\n};\n\nconst getHelloBlock = () => {\n  return new ContentBlock({\n    key: 'a',\n    type: 'unstyled',\n    text: 'hello',\n    characterList: Immutable.List(Immutable.Repeat(CharacterMetadata.EMPTY, 5)),\n  });\n};\n\nconst getSelection = () => {\n  return new SelectionState({\n    anchorKey: 'a',\n    anchorOffset: 0,\n    focusKey: 'a',\n    focusOffset: 0,\n    isBackward: false,\n    hasFocus: true,\n  });\n};\n\nconst getProps = (block, decorator) => {\n  return {\n    block,\n    tree: BlockTree.generate(ContentState.createFromText(''), block, decorator),\n    selection: getSelection(),\n    decorator: decorator || null,\n    forceSelection: false,\n    direction: UnicodeBidiDirection.LTR,\n    blockStyleFn: returnEmptyString,\n    styleSet: NONE,\n  };\n};\n\nconst arePropsEqual = (renderedChild, leafPropSet) => {\n  Object.keys(leafPropSet).forEach(key => {\n    expect(\n      Immutable.is(leafPropSet[key], renderedChild.props[key]),\n    ).toMatchSnapshot();\n  });\n};\n\nconst assertLeaves = (renderedBlock, leafProps) => {\n  leafProps.forEach((leafPropSet, ii) => {\n    const child = renderedBlock[ii];\n    expect(child.type).toBe(DraftEditorLeaf);\n    arePropsEqual(child, leafPropSet);\n  });\n};\n\nbeforeEach(() => {\n  window.scrollTo.mockClear();\n  mockGetDecorations.mockClear();\n  mockLeafRender.mockClear();\n});\n\ntest('must render a leaf node', () => {\n  const props = getProps(getHelloBlock());\n  const block = ReactTestRenderer.create(<DraftEditorBlock {...props} />);\n  const blockInstance = block.root;\n\n  expect(blockInstance.children[0].type).toBe('div');\n\n  assertLeaves(blockInstance.children[0].children, [\n    {\n      text: 'hello',\n      offsetKey: 'a-0-0',\n      start: 0,\n      styleSet: NONE,\n      isLast: true,\n    },\n  ]);\n});\n\ntest('must render multiple leaf nodes', () => {\n  const boldLength = 2;\n  let helloBlock = getHelloBlock();\n  let characters = helloBlock.getCharacterList();\n  characters = characters\n    .slice(0, boldLength)\n    .map(c => CharacterMetadata.applyStyle(c, 'BOLD'))\n    .concat(characters.slice(boldLength));\n\n  helloBlock = helloBlock.set('characterList', characters.toList());\n\n  const props = getProps(helloBlock);\n  const block = ReactTestRenderer.create(<DraftEditorBlock {...props} />);\n  const blockInstance = block.root;\n\n  expect(blockInstance.children[0].type).toBe('div');\n\n  assertLeaves(blockInstance.children[0].children, [\n    {\n      /* eslint-disable-next-line fb-www/gender-neutral-language */\n      text: 'he',\n      offsetKey: 'a-0-0',\n      start: 0,\n      styleSet: BOLD,\n      isLast: false,\n    },\n    {\n      text: 'llo',\n      offsetKey: 'a-0-1',\n      start: 2,\n      styleSet: NONE,\n      isLast: true,\n    },\n  ]);\n});\n\ntest('must allow update when `block` has changed', () => {\n  const helloBlock = getHelloBlock();\n  const props = getProps(helloBlock);\n\n  const container = document.createElement('div');\n  ReactDOM.render(<DraftEditorBlock {...props} />, container);\n\n  expect(mockLeafRender.mock.calls.length).toMatchSnapshot();\n\n  const updatedHelloBlock = helloBlock.set('text', 'hxllo');\n  const nextProps = getProps(updatedHelloBlock);\n\n  expect(updatedHelloBlock !== helloBlock).toMatchSnapshot();\n  expect(props.block !== nextProps.block).toMatchSnapshot();\n\n  ReactDOM.render(<DraftEditorBlock {...nextProps} />, container);\n\n  expect(mockLeafRender.mock.calls.length).toMatchSnapshot();\n});\n\ntest('must allow update when `tree` has changed', () => {\n  const helloBlock = getHelloBlock();\n  const props = getProps(helloBlock);\n\n  const container = document.createElement('div');\n  ReactDOM.render(<DraftEditorBlock {...props} />, container);\n\n  expect(mockLeafRender.mock.calls.length).toMatchSnapshot();\n\n  mockGetDecorations.mockReturnValue(\n    Immutable.List.of('x', 'x', null, null, null),\n  );\n  const decorator = new Decorator();\n\n  const newTree = BlockTree.generate(\n    ContentState.createFromText(helloBlock.getText()),\n    helloBlock,\n    decorator,\n  );\n  const nextProps = {...props, tree: newTree, decorator};\n\n  expect(props.tree !== nextProps.tree).toMatchSnapshot();\n\n  ReactDOM.render(<DraftEditorBlock {...nextProps} />, container);\n\n  expect(mockLeafRender.mock.calls.length).toMatchSnapshot();\n});\n\ntest('must allow update when `direction` has changed', () => {\n  const helloBlock = getHelloBlock();\n  const props = getProps(helloBlock);\n\n  const container = document.createElement('div');\n  ReactDOM.render(<DraftEditorBlock {...props} />, container);\n\n  expect(mockLeafRender.mock.calls.length).toMatchSnapshot();\n\n  const nextProps = {...props, direction: UnicodeBidiDirection.RTL};\n  expect(props.direction !== nextProps.direction).toMatchSnapshot();\n\n  ReactDOM.render(<DraftEditorBlock {...nextProps} />, container);\n\n  expect(mockLeafRender.mock.calls.length).toMatchSnapshot();\n});\n\ntest('must allow update when forcing selection', () => {\n  const helloBlock = getHelloBlock();\n  const props = getProps(helloBlock);\n\n  const container = document.createElement('div');\n  ReactDOM.render(<DraftEditorBlock {...props} />, container);\n\n  expect(mockLeafRender.mock.calls.length).toMatchSnapshot();\n\n  // The default selection state in this test is on a selection edge.\n  const nextProps = {\n    ...props,\n    forceSelection: true,\n  };\n\n  ReactDOM.render(<DraftEditorBlock {...nextProps} />, container);\n\n  expect(mockLeafRender.mock.calls.length).toMatchSnapshot();\n});\n\ntest('must reject update if conditions are not met', () => {\n  const helloBlock = getHelloBlock();\n  const props = getProps(helloBlock);\n\n  const container = document.createElement('div');\n  ReactDOM.render(<DraftEditorBlock {...props} />, container);\n\n  expect(mockLeafRender.mock.calls.length).toMatchSnapshot();\n\n  // Render again with the exact same props as before.\n  ReactDOM.render(<DraftEditorBlock {...props} />, container);\n\n  // No new leaf renders.\n  expect(mockLeafRender.mock.calls.length).toMatchSnapshot();\n});\n\ntest('must reject update if selection is not on an edge', () => {\n  const helloBlock = getHelloBlock();\n  const props = getProps(helloBlock);\n\n  const container = document.createElement('div');\n  ReactDOM.render(<DraftEditorBlock {...props} />, container);\n\n  expect(mockLeafRender.mock.calls.length).toMatchSnapshot();\n\n  // Move selection state to some other block.\n  const nonEdgeSelection = props.selection.merge({\n    anchorKey: 'z',\n    focusKey: 'z',\n  });\n\n  const newProps = {...props, selection: nonEdgeSelection};\n\n  // Render again with selection now moved elsewhere and the contents\n  // unchanged.\n  ReactDOM.render(<DraftEditorBlock {...newProps} />, container);\n\n  // No new leaf renders.\n  expect(mockLeafRender.mock.calls.length).toMatchSnapshot();\n});\n\ntest('must split apart two decorated and undecorated', () => {\n  const helloBlock = getHelloBlock();\n\n  mockGetDecorations.mockReturnValue(\n    Immutable.List.of('x', 'x', null, null, null),\n  );\n  const decorator = new Decorator();\n  const props = getProps(helloBlock, decorator);\n\n  const container = document.createElement('div');\n  const block = ReactTestRenderer.create(\n    <DraftEditorBlock {...props} />,\n    container,\n  );\n  const blockInstance = block.root;\n\n  expect(mockLeafRender.mock.calls.length).toMatchSnapshot();\n\n  const el = blockInstance.children[0];\n  expect(el.type).toBe('div');\n\n  arePropsEqual(el.children[0], {offsetKey: 'a-0-0'});\n  expect(el.children[0].type).toBe(DecoratorSpan);\n  expect(el.children[0].children.length).toBe(1);\n  expect(el.children[0].children[0].type).toBe('span');\n\n  arePropsEqual(el.children[1], {offsetKey: 'a-1-0'});\n  expect(el.children[1].type).toBe(DraftEditorLeaf);\n});\n\ntest('must split apart two decorators', () => {\n  const helloBlock = getHelloBlock();\n\n  mockGetDecorations.mockReturnValue(\n    Immutable.List.of('x', 'x', 'y', 'y', 'y'),\n  );\n\n  const decorator = new Decorator();\n  const props = getProps(helloBlock, decorator);\n\n  const container = document.createElement('div');\n  const block = ReactTestRenderer.create(\n    <DraftEditorBlock {...props} />,\n    container,\n  );\n  const blockInstance = block.root;\n\n  expect(mockLeafRender.mock.calls.length).toMatchSnapshot();\n\n  const el = blockInstance.children[0];\n  expect(el.type).toBe('div');\n\n  arePropsEqual(el.children[0], {offsetKey: 'a-0-0'});\n  expect(el.children[0].type).toBe(DecoratorSpan);\n  expect(el.children[0].children.length).toBe(1);\n  expect(el.children[0].children[0].type).toBe('span');\n\n  arePropsEqual(el.children[1], {offsetKey: 'a-1-0'});\n  expect(el.children[1].type).toBe(DecoratorSpan);\n});\n\ntest('must split apart styled spans', () => {\n  let helloBlock = getHelloBlock();\n  const characters = helloBlock.getCharacterList();\n  const newChars = characters\n    .slice(0, 2)\n    .map(ch => {\n      return CharacterMetadata.applyStyle(ch, 'BOLD');\n    })\n    .concat(characters.slice(2));\n\n  helloBlock = helloBlock.set('characterList', Immutable.List(newChars));\n  const props = getProps(helloBlock);\n\n  const container = document.createElement('div');\n  const block = ReactTestRenderer.create(\n    <DraftEditorBlock {...props} />,\n    container,\n  );\n  const blockInstance = block.root;\n\n  expect(mockLeafRender.mock.calls.length).toMatchSnapshot();\n\n  const el = blockInstance.children[0];\n  expect(el.type).toBe('div');\n\n  arePropsEqual(el.children[0], {offsetKey: 'a-0-0', styleSet: BOLD});\n  expect(el.children[0].type).toBe(DraftEditorLeaf);\n\n  arePropsEqual(el.children[1], {offsetKey: 'a-0-1', styleSet: NONE});\n  expect(el.children[1].type).toBe(DraftEditorLeaf);\n});\n\ntest('must split styled spans apart within decorator', () => {\n  let helloBlock = getHelloBlock();\n  const characters = helloBlock.getCharacterList();\n  const newChars = Immutable.List([\n    CharacterMetadata.applyStyle(characters.get(0), 'BOLD'),\n    CharacterMetadata.applyStyle(characters.get(1), 'ITALIC'),\n  ]).concat(characters.slice(2));\n\n  helloBlock = helloBlock.set('characterList', Immutable.List(newChars));\n\n  mockGetDecorations.mockReturnValue(\n    Immutable.List.of('x', 'x', null, null, null),\n  );\n  const decorator = new Decorator();\n  const props = getProps(helloBlock, decorator);\n\n  const container = document.createElement('div');\n  const block = ReactTestRenderer.create(\n    <DraftEditorBlock {...props} />,\n    container,\n  );\n  const blockInstance = block.root;\n\n  expect(mockLeafRender.mock.calls.length).toMatchSnapshot();\n\n  const el = blockInstance.children[0];\n  expect(el.type).toBe('div');\n\n  arePropsEqual(el.children[0], {offsetKey: 'a-0-0'});\n  expect(el.children[0].type).toBe(DecoratorSpan);\n\n  const renderer = el.children[0].props;\n  arePropsEqual(renderer.children[0], {offsetKey: 'a-0-0', styleSet: BOLD});\n  expect(renderer.children[0].type).toBe(DraftEditorLeaf);\n\n  arePropsEqual(renderer.children[1], {\n    offsetKey: 'a-0-1',\n    styleSet: ITALIC,\n  });\n  expect(renderer.children[0].type).toBe(DraftEditorLeaf);\n\n  arePropsEqual(el.children[1], {offsetKey: 'a-1-0', styleSet: NONE});\n  expect(el.children[1].type).toBe(DraftEditorLeaf);\n});\n\ntest('must scroll the window if needed', () => {\n  const props = getProps(getHelloBlock());\n\n  getElementPosition.mockReturnValueOnce({\n    x: 0,\n    y: 800,\n    width: 500,\n    height: 16,\n  });\n\n  const container = document.createElement('div');\n  ReactDOM.render(<DraftEditorBlock {...props} />, container);\n\n  const scrollCalls = window.scrollTo.mock.calls;\n  expect(scrollCalls).toMatchSnapshot();\n});\n\ntest('must not scroll the window if unnecessary', () => {\n  const props = getProps(getHelloBlock());\n  const container = document.createElement('div');\n  ReactDOM.render(<DraftEditorBlock {...props} />, container);\n\n  const scrollCalls = window.scrollTo.mock.calls;\n  expect(scrollCalls).toMatchSnapshot();\n});\n"
  },
  {
    "path": "src/component/contents/__tests__/DraftEditorContents.react-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\njest.mock('generateRandomKey');\n\nconst Editor = require('DraftEditor.react');\nconst EditorState = require('EditorState');\nconst RichUtils = require('RichTextEditorUtil');\n\nconst React = require('react');\nconst ReactTestRenderer = require('react-test-renderer');\n\ntest('defaults to \"unstyled\" block type for unknown block types', () => {\n  const CUSTOM_BLOCK_TYPE = 'CUSTOM_BLOCK_TYPE';\n\n  function CustomText(props) {\n    // contrived example\n    return (\n      <p>\n        <b>{props.children}</b>\n      </p>\n    );\n  }\n\n  class Container extends React.Component {\n    constructor(props) {\n      super(props);\n      this.state = {\n        editorState: EditorState.createEmpty(),\n      };\n    }\n    toggleCustomBlock = () => {\n      this.setState(\n        {\n          editorState: RichUtils.toggleBlockType(\n            this.state.editorState,\n            CUSTOM_BLOCK_TYPE,\n          ),\n        },\n        () => {\n          setTimeout(() => this.focus(), 0);\n        },\n      );\n    };\n    blockRenderFn(block) {\n      if (block.getType() === CUSTOM_BLOCK_TYPE) {\n        return {\n          component: CustomText,\n          editable: true,\n        };\n      }\n      return null;\n    }\n    render() {\n      return (\n        <div className=\"container-root\">\n          <div>\n            <button onClick={this.toggleCustomBlock}>CenterAlign</button>\n          </div>\n          <Editor\n            placeholder=\"Type away :)\"\n            editorState={this.state.editorState}\n            blockRendererFn={this.blockRenderFn}\n            onChange={this._handleChange}\n          />\n        </div>\n      );\n    }\n    _handleChange = editorState => {\n      this.setState({editorState});\n    };\n  }\n\n  const block = ReactTestRenderer.create(<Container />);\n  const editorInstace = block.getInstance();\n\n  expect(() => {\n    editorInstace.toggleCustomBlock(\n      editorInstace.state.editorState,\n      CUSTOM_BLOCK_TYPE,\n    );\n  }).not.toThrow();\n});\n"
  },
  {
    "path": "src/component/contents/__tests__/DraftEditorTextNode-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\njest.mock('UserAgent');\n\nconst BLOCK_DELIMITER_CHAR = '\\n';\nconst TEST_A = 'Hello';\nconst TEST_B = ' World!';\n\nconst DraftEditorTextNode = require('DraftEditorTextNode.react');\nconst ReactDOM = require('ReactDOM');\nconst UserAgent = require('UserAgent');\n\nconst React = require('react');\n\nlet container;\n\nbeforeEach(() => {\n  jest.resetModules();\n  container = document.createElement('div');\n});\n\nconst renderIntoContainer = (element: React.Node) => {\n  // $FlowFixMe[incompatible-call]\n  // $FlowFixMe[incompatible-exact]\n  return ReactDOM.render(element, container);\n};\n\nconst initializeAsIE = () => {\n  /* $FlowFixMe[prop-missing] (>=0.99.0 site=www) This comment suppresses an\n   * error found when Flow v0.47 was deployed. To see the error delete this\n   * comment and run Flow. */\n  UserAgent.isBrowser.mockImplementation(() => true);\n};\n\nconst initializeAsNonIE = () => {\n  /* $FlowFixMe[prop-missing] (>=0.99.0 site=www) This comment suppresses an\n   * error found when Flow v0.47 was deployed. To see the error delete this\n   * comment and run Flow. */\n  UserAgent.isBrowser.mockImplementation(() => false);\n};\n\nconst expectPopulatedSpan = (\n  stub: DraftEditorTextNode | HTMLDivElement,\n  testString: string | $TEMPORARY$string<'Hello'>,\n) => {\n  // $FlowExpectedError[incompatible-type] node could be null\n  const node: Element = ReactDOM.findDOMNode(stub);\n  expect(node.tagName).toBe('SPAN');\n  expect(node.childNodes.length).toBe(1);\n  expect(node.firstChild && node.firstChild.textContent).toBe(testString);\n};\n\ntest('must initialize correctly with an empty string, non-IE', function () {\n  initializeAsNonIE();\n  const stub = renderIntoContainer(\n    <DraftEditorTextNode>{''}</DraftEditorTextNode>,\n  );\n  // $FlowExpectedError[incompatible-use] we know node is an Element\n  // $FlowExpectedError[prop-missing] we know node is an Element\n  expect(ReactDOM.findDOMNode(stub).tagName).toBe('BR');\n});\n\ntest('must initialize correctly with an empty string, IE', function () {\n  initializeAsIE();\n  const stub = renderIntoContainer(\n    <DraftEditorTextNode>{''}</DraftEditorTextNode>,\n  );\n  expectPopulatedSpan(stub, BLOCK_DELIMITER_CHAR);\n});\n\ntest('must initialize correctly with a string, non-IE', function () {\n  initializeAsNonIE();\n  const stub = renderIntoContainer(\n    <DraftEditorTextNode>{TEST_A}</DraftEditorTextNode>,\n  );\n  expectPopulatedSpan(stub, TEST_A);\n});\n\ntest('must initialize correctly with a string, IE', function () {\n  initializeAsIE();\n  const stub = renderIntoContainer(\n    <DraftEditorTextNode>{TEST_A}</DraftEditorTextNode>,\n  );\n  expectPopulatedSpan(stub, TEST_A);\n});\n\ntest('must update from empty to non-empty, non-IE', function () {\n  initializeAsNonIE();\n  const stub = renderIntoContainer(\n    <DraftEditorTextNode>{''}</DraftEditorTextNode>,\n  );\n\n  renderIntoContainer(<DraftEditorTextNode>{TEST_A}</DraftEditorTextNode>);\n  expectPopulatedSpan(stub, TEST_A);\n});\n\ntest('must update from empty to non-empty, IE', function () {\n  initializeAsIE();\n  const stub = renderIntoContainer(\n    <DraftEditorTextNode>{''}</DraftEditorTextNode>,\n  );\n\n  renderIntoContainer(<DraftEditorTextNode>{TEST_A}</DraftEditorTextNode>);\n  expectPopulatedSpan(stub, TEST_A);\n});\n\ntest('must update from non-empty to non-empty, non-IE', function () {\n  initializeAsNonIE();\n  const stub = renderIntoContainer(\n    <DraftEditorTextNode>{TEST_A}</DraftEditorTextNode>,\n  );\n\n  renderIntoContainer(\n    <DraftEditorTextNode>{TEST_A + TEST_B}</DraftEditorTextNode>,\n  );\n\n  expectPopulatedSpan(stub, TEST_A + TEST_B);\n\n  renderIntoContainer(<DraftEditorTextNode>{TEST_B}</DraftEditorTextNode>);\n  expectPopulatedSpan(stub, TEST_B);\n});\n\ntest('must update from non-empty to non-empty, non-IE', function () {\n  initializeAsIE();\n  const stub = renderIntoContainer(\n    <DraftEditorTextNode>{TEST_A}</DraftEditorTextNode>,\n  );\n\n  renderIntoContainer(\n    <DraftEditorTextNode>{TEST_A + TEST_B}</DraftEditorTextNode>,\n  );\n  expectPopulatedSpan(stub, TEST_A + TEST_B);\n\n  renderIntoContainer(<DraftEditorTextNode>{TEST_B}</DraftEditorTextNode>);\n  expectPopulatedSpan(stub, TEST_B);\n});\n\ntest('must skip updates if text already matches DOM, non-IE', function () {\n  initializeAsNonIE();\n  const stub = renderIntoContainer(\n    <DraftEditorTextNode>{TEST_A}</DraftEditorTextNode>,\n  );\n\n  jest.spyOn(stub, 'render');\n\n  renderIntoContainer(<DraftEditorTextNode>{TEST_A}</DraftEditorTextNode>);\n\n  expect(stub.render.mock.calls.length).toBe(0);\n\n  // Sanity check that updating is performed when appropriate.\n  renderIntoContainer(<DraftEditorTextNode>{TEST_B}</DraftEditorTextNode>);\n\n  expect(stub.render.mock.calls.length).toBe(1);\n});\n\ntest('must skip updates if text already matches DOM, IE', function () {\n  initializeAsIE();\n  const stub = renderIntoContainer(\n    <DraftEditorTextNode>{TEST_A}</DraftEditorTextNode>,\n  );\n\n  jest.spyOn(stub, 'render');\n\n  renderIntoContainer(<DraftEditorTextNode>{TEST_A}</DraftEditorTextNode>);\n\n  expect(stub.render.mock.calls.length).toBe(0);\n\n  // Sanity check that updating is performed when appropriate.\n  renderIntoContainer(<DraftEditorTextNode>{TEST_B}</DraftEditorTextNode>);\n\n  expect(stub.render.mock.calls.length).toBe(1);\n});\n\ntest('must update from non-empty to empty, non-IE', function () {\n  initializeAsNonIE();\n  const stub = renderIntoContainer(\n    <DraftEditorTextNode>{TEST_A}</DraftEditorTextNode>,\n  );\n\n  renderIntoContainer(<DraftEditorTextNode>{''}</DraftEditorTextNode>);\n\n  // $FlowExpectedError[incompatible-use] we know node is an Element\n  // $FlowExpectedError[prop-missing] we know node is an Element\n  expect(ReactDOM.findDOMNode(stub).tagName).toBe('BR');\n});\n\ntest('must update from non-empty to empty, IE', function () {\n  initializeAsIE();\n  const stub = renderIntoContainer(\n    <DraftEditorTextNode>{TEST_A}</DraftEditorTextNode>,\n  );\n\n  renderIntoContainer(<DraftEditorTextNode>{''}</DraftEditorTextNode>);\n\n  expectPopulatedSpan(stub, BLOCK_DELIMITER_CHAR);\n});\n\ntest('must render properly into a parent DOM node', function () {\n  initializeAsNonIE();\n  renderIntoContainer(\n    <div>\n      <DraftEditorTextNode>{TEST_A}</DraftEditorTextNode>\n    </div>,\n  );\n});\n\ntest('must force unchanged text back into the DOM', function () {\n  initializeAsNonIE();\n  const stub = renderIntoContainer(\n    <DraftEditorTextNode>{TEST_A}</DraftEditorTextNode>,\n  );\n\n  // $FlowExpectedError[incompatible-use] we know node is not null\n  ReactDOM.findDOMNode(stub).textContent = TEST_B;\n\n  renderIntoContainer(<DraftEditorTextNode>{TEST_A}</DraftEditorTextNode>);\n\n  // $FlowExpectedError[incompatible-use] we know node is not null\n  expect(ReactDOM.findDOMNode(stub).textContent).toBe(TEST_A);\n});\n"
  },
  {
    "path": "src/component/contents/__tests__/__snapshots__/DraftEditorBlock.react-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must allow update when \\`block\\` has changed 1`] = `1`;\n\nexports[`must allow update when \\`block\\` has changed 2`] = `true`;\n\nexports[`must allow update when \\`block\\` has changed 3`] = `true`;\n\nexports[`must allow update when \\`block\\` has changed 4`] = `2`;\n\nexports[`must allow update when \\`direction\\` has changed 1`] = `1`;\n\nexports[`must allow update when \\`direction\\` has changed 2`] = `true`;\n\nexports[`must allow update when \\`direction\\` has changed 3`] = `2`;\n\nexports[`must allow update when \\`tree\\` has changed 1`] = `1`;\n\nexports[`must allow update when \\`tree\\` has changed 2`] = `true`;\n\nexports[`must allow update when \\`tree\\` has changed 3`] = `3`;\n\nexports[`must allow update when forcing selection 1`] = `1`;\n\nexports[`must allow update when forcing selection 2`] = `2`;\n\nexports[`must not scroll the window if unnecessary 1`] = `Array []`;\n\nexports[`must reject update if conditions are not met 1`] = `1`;\n\nexports[`must reject update if conditions are not met 2`] = `1`;\n\nexports[`must reject update if selection is not on an edge 1`] = `1`;\n\nexports[`must reject update if selection is not on an edge 2`] = `1`;\n\nexports[`must render a leaf node 1`] = `true`;\n\nexports[`must render a leaf node 2`] = `true`;\n\nexports[`must render a leaf node 3`] = `true`;\n\nexports[`must render a leaf node 4`] = `true`;\n\nexports[`must render a leaf node 5`] = `true`;\n\nexports[`must render multiple leaf nodes 1`] = `true`;\n\nexports[`must render multiple leaf nodes 2`] = `true`;\n\nexports[`must render multiple leaf nodes 3`] = `true`;\n\nexports[`must render multiple leaf nodes 4`] = `true`;\n\nexports[`must render multiple leaf nodes 5`] = `true`;\n\nexports[`must render multiple leaf nodes 6`] = `true`;\n\nexports[`must render multiple leaf nodes 7`] = `true`;\n\nexports[`must render multiple leaf nodes 8`] = `true`;\n\nexports[`must render multiple leaf nodes 9`] = `true`;\n\nexports[`must render multiple leaf nodes 10`] = `true`;\n\nexports[`must scroll the window if needed 1`] = `\nArray [\n  Array [\n    0,\n    26,\n  ],\n]\n`;\n\nexports[`must split apart styled spans 1`] = `2`;\n\nexports[`must split apart styled spans 2`] = `true`;\n\nexports[`must split apart styled spans 3`] = `true`;\n\nexports[`must split apart styled spans 4`] = `true`;\n\nexports[`must split apart styled spans 5`] = `true`;\n\nexports[`must split apart two decorated and undecorated 1`] = `2`;\n\nexports[`must split apart two decorated and undecorated 2`] = `true`;\n\nexports[`must split apart two decorated and undecorated 3`] = `true`;\n\nexports[`must split apart two decorators 1`] = `2`;\n\nexports[`must split apart two decorators 2`] = `true`;\n\nexports[`must split apart two decorators 3`] = `true`;\n\nexports[`must split styled spans apart within decorator 1`] = `3`;\n\nexports[`must split styled spans apart within decorator 2`] = `true`;\n\nexports[`must split styled spans apart within decorator 3`] = `true`;\n\nexports[`must split styled spans apart within decorator 4`] = `true`;\n\nexports[`must split styled spans apart within decorator 5`] = `true`;\n\nexports[`must split styled spans apart within decorator 6`] = `true`;\n\nexports[`must split styled spans apart within decorator 7`] = `true`;\n\nexports[`must split styled spans apart within decorator 8`] = `true`;\n"
  },
  {
    "path": "src/component/contents/exploration/DraftEditorBlockNode.react.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * This file is a fork of DraftEditorBlock.react.js and DraftEditorContents.react.js\n *\n * This is unstable and not part of the public API and should not be used by\n * production systems. This file may be update/removed without notice.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type ContentState from 'ContentState';\nimport type {DraftBlockRenderMap} from 'DraftBlockRenderMap';\nimport type {DraftDecoratorType} from 'DraftDecoratorType';\nimport type {DraftInlineStyle} from 'DraftInlineStyle';\nimport type EditorState from 'EditorState';\nimport type SelectionState from 'SelectionState';\nimport type {BidiDirection} from 'UnicodeBidiDirection';\n\nconst DraftEditorNode = require('DraftEditorNode.react');\nconst DraftOffsetKey = require('DraftOffsetKey');\nconst Scroll = require('Scroll');\nconst Style = require('Style');\n\nconst getElementPosition = require('getElementPosition');\nconst getScrollPosition = require('getScrollPosition');\nconst getViewportDimensions = require('getViewportDimensions');\nconst Immutable = require('immutable');\nconst invariant = require('invariant');\nconst isHTMLElement = require('isHTMLElement');\nconst React = require('react');\n\nconst SCROLL_BUFFER = 10;\n\nconst {List} = Immutable;\n\n// we should harden up the below flow types to make them more strict\ntype CustomRenderConfig = Object;\ntype DraftRenderConfig = Object;\ntype BlockRenderFn = (block: BlockNodeRecord) => ?Object;\ntype BlockStyleFn = (block: BlockNodeRecord) => string;\n\ntype Props = {\n  block: BlockNodeRecord,\n  blockProps?: Object,\n  blockRenderMap: DraftBlockRenderMap,\n  blockRendererFn: BlockRenderFn,\n  blockStyleFn: BlockStyleFn,\n  contentState: ContentState,\n  customStyleFn: (style: DraftInlineStyle, block: BlockNodeRecord) => ?Object,\n  customStyleMap: Object,\n  decorator: ?DraftDecoratorType,\n  direction: BidiDirection,\n  editorKey: string,\n  editorState: EditorState,\n  forceSelection: boolean,\n  selection: SelectionState,\n  startIndent?: boolean,\n  tree: List<any>,\n  ...\n};\n\n/**\n * Return whether a block overlaps with either edge of the `SelectionState`.\n */\nconst isBlockOnSelectionEdge = (\n  selection: SelectionState,\n  key: string,\n): boolean => {\n  return selection.getAnchorKey() === key || selection.getFocusKey() === key;\n};\n\n/**\n * We will use this helper to identify blocks that need to be wrapped but have siblings that\n * also share the same wrapper element, this way we can do the wrapping once the last sibling\n * is added.\n */\nconst shouldNotAddWrapperElement = (\n  block: BlockNodeRecord,\n  contentState: ContentState,\n): boolean => {\n  const nextSiblingKey = block.getNextSiblingKey();\n\n  return nextSiblingKey\n    ? contentState.getBlockForKey(nextSiblingKey).getType() === block.getType()\n    : false;\n};\n\nconst applyWrapperElementToSiblings = (\n  wrapperTemplate: any,\n  Element: string,\n  nodes: Array<React.Node>,\n): Array<React.Node> => {\n  const wrappedSiblings = [];\n\n  // we check back until we find a sibling that does not have same wrapper\n  for (const sibling: any of nodes.reverse()) {\n    if (sibling.type !== Element) {\n      break;\n    }\n    wrappedSiblings.push(sibling);\n  }\n\n  // we now should remove from acc the wrappedSiblings and add them back under same wrap\n  nodes.splice(nodes.indexOf(wrappedSiblings[0]), wrappedSiblings.length + 1);\n\n  const childrenIs = wrappedSiblings.reverse();\n\n  const key = childrenIs[0].key;\n\n  nodes.push(\n    React.cloneElement(\n      wrapperTemplate,\n      {\n        key: `${key}-wrap`,\n        'data-offset-key': DraftOffsetKey.encode(key, 0, 0),\n      },\n      childrenIs,\n    ),\n  );\n\n  return nodes;\n};\n\nconst getDraftRenderConfig = (\n  block: BlockNodeRecord,\n  blockRenderMap: DraftBlockRenderMap,\n): DraftRenderConfig => {\n  const configForType =\n    blockRenderMap.get(block.getType()) || blockRenderMap.get('unstyled');\n\n  const wrapperTemplate = configForType.wrapper;\n  const Element =\n    configForType.element || blockRenderMap.get('unstyled').element;\n\n  return {\n    Element,\n    wrapperTemplate,\n  };\n};\n\nconst getCustomRenderConfig = (\n  block: BlockNodeRecord,\n  blockRendererFn: BlockRenderFn,\n): CustomRenderConfig => {\n  const customRenderer = blockRendererFn(block);\n\n  if (!customRenderer) {\n    return {};\n  }\n\n  const {\n    component: CustomComponent,\n    props: customProps,\n    editable: customEditable,\n  } = customRenderer;\n\n  return {\n    CustomComponent,\n    customProps,\n    customEditable,\n  };\n};\n\nconst getElementPropsConfig = (\n  block: BlockNodeRecord,\n  editorKey: string,\n  offsetKey: string,\n  blockStyleFn: BlockStyleFn,\n  customConfig: CustomRenderConfig,\n  ref: null | {current: null | Element},\n): Object => {\n  let elementProps: Object = {\n    'data-block': true,\n    'data-editor': editorKey,\n    'data-offset-key': offsetKey,\n    key: block.getKey(),\n    ref,\n  };\n  const customClass = blockStyleFn(block);\n\n  if (customClass) {\n    elementProps.className = customClass;\n  }\n\n  if (customConfig.customEditable !== undefined) {\n    elementProps = {\n      ...elementProps,\n      contentEditable: customConfig.customEditable,\n      suppressContentEditableWarning: true,\n    };\n  }\n\n  return elementProps;\n};\n\nclass DraftEditorBlockNode extends React.Component<Props> {\n  wrapperRef: {current: null | Element} = React.createRef<Element>();\n\n  shouldComponentUpdate(nextProps: Props): boolean {\n    const {block, direction, tree} = this.props;\n    const isContainerNode = !block.getChildKeys().isEmpty();\n    const blockHasChanged =\n      block !== nextProps.block ||\n      tree !== nextProps.tree ||\n      direction !== nextProps.direction ||\n      (isBlockOnSelectionEdge(nextProps.selection, nextProps.block.getKey()) &&\n        nextProps.forceSelection);\n\n    // if we have children at this stage we always re-render container nodes\n    // else if its a root node we avoid re-rendering by checking for block updates\n    return isContainerNode || blockHasChanged;\n  }\n\n  /**\n   * When a block is mounted and overlaps the selection state, we need to make\n   * sure that the cursor is visible to match native behavior. This may not\n   * be the case if the user has pressed `RETURN` or pasted some content, since\n   * programatically creating these new blocks and setting the DOM selection\n   * will miss out on the browser natively scrolling to that position.\n   *\n   * To replicate native behavior, if the block overlaps the selection state\n   * on mount, force the scroll position. Check the scroll state of the scroll\n   * parent, and adjust it to align the entire block to the bottom of the\n   * scroll parent.\n   */\n  componentDidMount(): void {\n    const selection = this.props.selection;\n    const endKey = selection.getEndKey();\n    if (!selection.getHasFocus() || endKey !== this.props.block.getKey()) {\n      return;\n    }\n\n    const blockNode = this.wrapperRef.current;\n    if (!blockNode) {\n      // This Block Node was rendered without a wrapper element.\n      return;\n    }\n    const scrollParent = Style.getScrollParent(blockNode);\n    const scrollPosition = getScrollPosition(scrollParent);\n    let scrollDelta;\n\n    if (scrollParent === window) {\n      const nodePosition = getElementPosition(blockNode);\n      const nodeBottom = nodePosition.y + nodePosition.height;\n      const viewportHeight = getViewportDimensions().height;\n      scrollDelta = nodeBottom - viewportHeight;\n      if (scrollDelta > 0) {\n        window.scrollTo(\n          scrollPosition.x,\n          scrollPosition.y + scrollDelta + SCROLL_BUFFER,\n        );\n      }\n    } else {\n      invariant(isHTMLElement(blockNode), 'blockNode is not an HTMLElement');\n      const htmlBlockNode: HTMLElement = (blockNode: any);\n      const blockBottom = htmlBlockNode.offsetHeight + htmlBlockNode.offsetTop;\n      const scrollBottom = scrollParent.offsetHeight + scrollPosition.y;\n      scrollDelta = blockBottom - scrollBottom;\n      if (scrollDelta > 0) {\n        Scroll.setTop(\n          scrollParent,\n          Scroll.getTop(scrollParent) + scrollDelta + SCROLL_BUFFER,\n        );\n      }\n    }\n  }\n\n  render(): React.Node {\n    const {\n      block,\n      blockRenderMap,\n      blockRendererFn,\n      blockStyleFn,\n      contentState,\n      decorator,\n      editorKey,\n      editorState,\n      customStyleFn,\n      customStyleMap,\n      direction,\n      forceSelection,\n      selection,\n      tree,\n    } = this.props;\n\n    let children = null;\n\n    if (block.children.size) {\n      children = block.children.reduce((acc, key) => {\n        const offsetKey = DraftOffsetKey.encode(key, 0, 0);\n        const child = contentState.getBlockForKey(key);\n        const customConfig = getCustomRenderConfig(child, blockRendererFn);\n        const Component = customConfig.CustomComponent || DraftEditorBlockNode;\n        const {Element, wrapperTemplate} = getDraftRenderConfig(\n          child,\n          blockRenderMap,\n        );\n        const elementProps = getElementPropsConfig(\n          child,\n          editorKey,\n          offsetKey,\n          blockStyleFn,\n          customConfig,\n          null,\n        );\n        const childProps = {\n          ...this.props,\n          tree: editorState.getBlockTree(key),\n          blockProps: customConfig.customProps,\n          offsetKey,\n          block: child,\n        };\n\n        acc.push(\n          React.createElement(\n            Element,\n            elementProps,\n            <Component {...childProps} />,\n          ),\n        );\n\n        if (\n          !wrapperTemplate ||\n          shouldNotAddWrapperElement(child, contentState)\n        ) {\n          return acc;\n        }\n\n        // if we are here it means we are the last block\n        // that has a wrapperTemplate so we should wrap itself\n        // and all other previous siblings that share the same wrapper\n        applyWrapperElementToSiblings(wrapperTemplate, Element, acc);\n\n        return acc;\n      }, []);\n    }\n\n    const blockKey = block.getKey();\n    const offsetKey = DraftOffsetKey.encode(blockKey, 0, 0);\n\n    const customConfig = getCustomRenderConfig(block, blockRendererFn);\n    const Component = customConfig.CustomComponent;\n    const blockNode =\n      Component != null ? (\n        <Component\n          {...this.props}\n          tree={editorState.getBlockTree(blockKey)}\n          blockProps={customConfig.customProps}\n          offsetKey={offsetKey}\n          block={block}\n        />\n      ) : (\n        <DraftEditorNode\n          block={block}\n          children={children}\n          contentState={contentState}\n          customStyleFn={customStyleFn}\n          customStyleMap={customStyleMap}\n          decorator={decorator}\n          direction={direction}\n          forceSelection={forceSelection}\n          hasSelection={isBlockOnSelectionEdge(selection, blockKey)}\n          selection={selection}\n          tree={tree}\n        />\n      );\n\n    if (block.getParentKey()) {\n      return blockNode;\n    }\n\n    const {Element} = getDraftRenderConfig(block, blockRenderMap);\n    const elementProps = getElementPropsConfig(\n      block,\n      editorKey,\n      offsetKey,\n      blockStyleFn,\n      customConfig,\n      this.wrapperRef,\n    );\n\n    // root block nodes needs to be wrapped\n    return React.createElement(Element, elementProps, blockNode);\n  }\n}\n\nmodule.exports = DraftEditorBlockNode;\n"
  },
  {
    "path": "src/component/contents/exploration/DraftEditorContentsExperimental.react.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * This file is a fork of DraftEditorContents.react.js for tree nodes\n *\n * This is unstable and not part of the public API and should not be used by\n * production systems. This file may be update/removed without notice.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type {DraftBlockRenderMap} from 'DraftBlockRenderMap';\nimport type {DraftInlineStyle} from 'DraftInlineStyle';\nimport type EditorState from 'EditorState';\nimport type {BidiDirection} from 'UnicodeBidiDirection';\n\nconst DraftEditorBlockNode = require('DraftEditorBlockNode.react');\nconst DraftOffsetKey = require('DraftOffsetKey');\n\nconst nullthrows = require('nullthrows');\nconst React = require('react');\n\ntype Props = {\n  blockRenderMap: DraftBlockRenderMap,\n  blockRendererFn: (block: BlockNodeRecord) => ?Object,\n  blockStyleFn?: (block: BlockNodeRecord) => string,\n  customStyleFn?: (style: DraftInlineStyle, block: BlockNodeRecord) => ?Object,\n  customStyleMap?: Object,\n  editorKey?: string,\n  editorState: EditorState,\n  textDirectionality?: BidiDirection,\n  ...\n};\n\n/**\n * `DraftEditorContents` is the container component for all block components\n * rendered for a `DraftEditor`. It is optimized to aggressively avoid\n * re-rendering blocks whenever possible.\n *\n * This component is separate from `DraftEditor` because certain props\n * (for instance, ARIA props) must be allowed to update without affecting\n * the contents of the editor.\n */\nclass DraftEditorContentsExperimental extends React.Component<Props> {\n  shouldComponentUpdate(nextProps: Props): boolean {\n    const prevEditorState = this.props.editorState;\n    const nextEditorState = nextProps.editorState;\n\n    const prevDirectionMap = prevEditorState.getDirectionMap();\n    const nextDirectionMap = nextEditorState.getDirectionMap();\n\n    // Text direction has changed for one or more blocks. We must re-render.\n    if (prevDirectionMap !== nextDirectionMap) {\n      return true;\n    }\n\n    const didHaveFocus = prevEditorState.getSelection().getHasFocus();\n    const nowHasFocus = nextEditorState.getSelection().getHasFocus();\n\n    if (didHaveFocus !== nowHasFocus) {\n      return true;\n    }\n\n    const nextNativeContent = nextEditorState.getNativelyRenderedContent();\n\n    const wasComposing = prevEditorState.isInCompositionMode();\n    const nowComposing = nextEditorState.isInCompositionMode();\n\n    // If the state is unchanged or we're currently rendering a natively\n    // rendered state, there's nothing new to be done.\n    if (\n      prevEditorState === nextEditorState ||\n      (nextNativeContent !== null &&\n        nextEditorState.getCurrentContent() === nextNativeContent) ||\n      (wasComposing && nowComposing)\n    ) {\n      return false;\n    }\n\n    const prevContent = prevEditorState.getCurrentContent();\n    const nextContent = nextEditorState.getCurrentContent();\n    const prevDecorator = prevEditorState.getDecorator();\n    const nextDecorator = nextEditorState.getDecorator();\n    return (\n      wasComposing !== nowComposing ||\n      prevContent !== nextContent ||\n      prevDecorator !== nextDecorator ||\n      nextEditorState.mustForceSelection()\n    );\n  }\n\n  render(): React.Node {\n    const {\n      blockRenderMap,\n      blockRendererFn,\n      blockStyleFn,\n      customStyleMap,\n      customStyleFn,\n      editorState,\n      editorKey,\n      textDirectionality,\n    } = this.props;\n\n    const content = editorState.getCurrentContent();\n    const selection = editorState.getSelection();\n    const forceSelection = editorState.mustForceSelection();\n    const decorator = editorState.getDecorator();\n    const directionMap = nullthrows(editorState.getDirectionMap());\n\n    const blocksAsArray = content.getBlocksAsArray();\n    const rootBlock = blocksAsArray[0];\n    const processedBlocks = [];\n\n    let nodeBlock: ?BlockNodeRecord = rootBlock;\n\n    while (nodeBlock) {\n      const blockKey = nodeBlock.getKey();\n      const blockProps = {\n        blockRenderMap,\n        blockRendererFn,\n        blockStyleFn,\n        contentState: content,\n        customStyleFn,\n        customStyleMap,\n        decorator,\n        editorKey,\n        editorState,\n        forceSelection,\n        selection,\n        block: nodeBlock,\n        direction: textDirectionality\n          ? textDirectionality\n          : directionMap.get(blockKey),\n        tree: editorState.getBlockTree(blockKey),\n      };\n\n      const configForType =\n        blockRenderMap.get(nodeBlock.getType()) ||\n        blockRenderMap.get('unstyled');\n      const wrapperTemplate = configForType.wrapper;\n      processedBlocks.push({\n        /* $FlowFixMe[incompatible-type] (>=0.112.0 site=www,mobile) This\n         * comment suppresses an error found when Flow v0.112 was deployed. To\n         * see the error delete this comment and run Flow. */\n        block: <DraftEditorBlockNode key={blockKey} {...blockProps} />,\n        wrapperTemplate,\n        key: blockKey,\n        offsetKey: DraftOffsetKey.encode(blockKey, 0, 0),\n      });\n\n      const nextBlockKey = nodeBlock.getNextSiblingKey();\n      nodeBlock = nextBlockKey ? content.getBlockForKey(nextBlockKey) : null;\n    }\n\n    // Group contiguous runs of blocks that have the same wrapperTemplate\n    const outputBlocks = [];\n    for (let ii = 0; ii < processedBlocks.length; ) {\n      const info: any = processedBlocks[ii];\n      if (info.wrapperTemplate) {\n        const blocks = [];\n        do {\n          blocks.push(processedBlocks[ii].block);\n          ii++;\n        } while (\n          ii < processedBlocks.length &&\n          processedBlocks[ii].wrapperTemplate === info.wrapperTemplate\n        );\n        const wrapperElement = React.cloneElement(\n          info.wrapperTemplate,\n          {\n            key: info.key + '-wrap',\n            'data-offset-key': info.offsetKey,\n          },\n          blocks,\n        );\n        outputBlocks.push(wrapperElement);\n      } else {\n        outputBlocks.push(info.block);\n        ii++;\n      }\n    }\n\n    return <div data-contents=\"true\">{outputBlocks}</div>;\n  }\n}\n\nmodule.exports = DraftEditorContentsExperimental;\n"
  },
  {
    "path": "src/component/contents/exploration/DraftEditorDecoratedLeaves.react.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * This is unstable and not part of the public API and should not be used by\n * production systems. This file may be update/removed without notice.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type ContentState from 'ContentState';\nimport type {DraftDecoratorType} from 'DraftDecoratorType';\nimport type {BidiDirection} from 'UnicodeBidiDirection';\nimport type {Set} from 'immutable';\n\nconst DraftOffsetKey = require('DraftOffsetKey');\nconst UnicodeBidi = require('UnicodeBidi');\nconst UnicodeBidiDirection = require('UnicodeBidiDirection');\n\nconst React = require('react');\n\ntype Props = {\n  block: BlockNodeRecord,\n  children: ?$ReadOnlyArray<React.Node>,\n  contentState: ContentState,\n  decorator: DraftDecoratorType,\n  decoratorKey: string,\n  direction: BidiDirection,\n  text: string,\n  leafSet: Set<any>,\n  ...\n};\n\nclass DraftEditorDecoratedLeaves extends React.Component<Props> {\n  render(): React.Node {\n    const {\n      block,\n      children,\n      contentState,\n      decorator,\n      decoratorKey,\n      direction,\n      leafSet,\n      text,\n    } = this.props;\n\n    const blockKey = block.getKey();\n    const leavesForLeafSet = leafSet.get('leaves');\n    const DecoratorComponent = decorator.getComponentForKey(decoratorKey);\n    const decoratorProps = decorator.getPropsForKey(decoratorKey);\n    const decoratorOffsetKey = DraftOffsetKey.encode(\n      blockKey,\n      parseInt(decoratorKey, 10),\n      0,\n    );\n\n    const decoratedText = text.slice(\n      leavesForLeafSet.first().get('start'),\n      leavesForLeafSet.last().get('end'),\n    );\n\n    // Resetting dir to the same value on a child node makes Chrome/Firefox\n    // confused on cursor movement. See http://jsfiddle.net/d157kLck/3/\n    const dir = UnicodeBidiDirection.getHTMLDirIfDifferent(\n      UnicodeBidi.getDirection(decoratedText),\n      direction,\n    );\n\n    return (\n      <DecoratorComponent\n        {...decoratorProps}\n        contentState={contentState}\n        decoratedText={decoratedText}\n        dir={dir}\n        key={decoratorOffsetKey}\n        entityKey={block.getEntityAt(leafSet.get('start'))}\n        offsetKey={decoratorOffsetKey}>\n        {children}\n      </DecoratorComponent>\n    );\n  }\n}\n\nmodule.exports = DraftEditorDecoratedLeaves;\n"
  },
  {
    "path": "src/component/contents/exploration/DraftEditorNode.react.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * This is unstable and not part of the public API and should not be used by\n * production systems. This file may be update/removed without notice.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type ContentState from 'ContentState';\nimport type {DraftDecoratorType} from 'DraftDecoratorType';\nimport type SelectionState from 'SelectionState';\nimport type {BidiDirection} from 'UnicodeBidiDirection';\n\nconst DraftEditorDecoratedLeaves = require('DraftEditorDecoratedLeaves.react');\nconst DraftEditorLeaf = require('DraftEditorLeaf.react');\nconst DraftOffsetKey = require('DraftOffsetKey');\n\nconst cx = require('cx');\nconst Immutable = require('immutable');\nconst React = require('react');\n\nconst {List} = Immutable;\n\ntype Props = {\n  block: BlockNodeRecord,\n  children: ?Array<React.Node>,\n  contentState: ContentState,\n  customStyleFn: Function,\n  customStyleMap: Object,\n  decorator: ?DraftDecoratorType,\n  direction: BidiDirection,\n  forceSelection: boolean,\n  hasSelection: boolean,\n  selection: SelectionState,\n  tree: List<any>,\n  ...\n};\n\nclass DraftEditorNode extends React.Component<Props> {\n  render(): React.Node {\n    const {\n      block,\n      contentState,\n      customStyleFn,\n      customStyleMap,\n      decorator,\n      direction,\n      forceSelection,\n      hasSelection,\n      selection,\n      tree,\n    } = this.props;\n\n    const blockKey = block.getKey();\n    const text = block.getText();\n    const lastLeafSet = tree.size - 1;\n\n    const children =\n      this.props.children ||\n      tree\n        .map((leafSet, ii) => {\n          const decoratorKey = leafSet.get('decoratorKey');\n          const leavesForLeafSet = leafSet.get('leaves');\n          const lastLeaf = leavesForLeafSet.size - 1;\n          const Leaves = leavesForLeafSet\n            .map((leaf, jj) => {\n              const offsetKey = DraftOffsetKey.encode(blockKey, ii, jj);\n              const start = leaf.get('start');\n              const end = leaf.get('end');\n              return (\n                <DraftEditorLeaf\n                  key={offsetKey}\n                  offsetKey={offsetKey}\n                  block={block}\n                  start={start}\n                  selection={hasSelection ? selection : null}\n                  forceSelection={forceSelection}\n                  text={text.slice(start, end)}\n                  styleSet={block.getInlineStyleAt(start)}\n                  customStyleMap={customStyleMap}\n                  customStyleFn={customStyleFn}\n                  isLast={decoratorKey === lastLeafSet && jj === lastLeaf}\n                />\n              );\n            })\n            .toArray();\n\n          if (!decoratorKey || !decorator) {\n            return Leaves;\n          }\n\n          return (\n            <DraftEditorDecoratedLeaves\n              block={block}\n              children={Leaves}\n              contentState={contentState}\n              decorator={decorator}\n              decoratorKey={decoratorKey}\n              direction={direction}\n              leafSet={leafSet}\n              text={text}\n              key={ii}\n            />\n          );\n        })\n        .toArray();\n\n    return (\n      <div\n        data-offset-key={DraftOffsetKey.encode(blockKey, 0, 0)}\n        className={cx({\n          'public/DraftStyleDefault/block': true,\n          'public/DraftStyleDefault/ltr': direction === 'LTR',\n          'public/DraftStyleDefault/rtl': direction === 'RTL',\n        })}>\n        {children}\n      </div>\n    );\n  }\n}\n\nmodule.exports = DraftEditorNode;\n"
  },
  {
    "path": "src/component/contents/exploration/__tests__/DraftEditorBlockNode.react-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\njest\n  .mock('Style')\n  .mock('getElementPosition')\n  .mock('getScrollPosition')\n  .mock('getViewportDimensions');\n\nconst BlockTree = require('BlockTree');\nconst CompositeDraftDecorator = require('CompositeDraftDecorator');\nconst ContentBlockNode = require('ContentBlockNode');\nconst ContentState = require('ContentState');\nconst DefaultDraftBlockRenderMap = require('DefaultDraftBlockRenderMap');\nconst DraftEditorBlockNode = require('DraftEditorBlockNode.react');\nconst EditorState = require('EditorState');\nconst SelectionState = require('SelectionState');\nconst Style = require('Style');\nconst UnicodeBidiDirection = require('UnicodeBidiDirection');\n\nconst TestHelper = require('_DraftTestHelper');\nconst getElementPosition = require('getElementPosition');\nconst getScrollPosition = require('getScrollPosition');\nconst getViewportDimensions = require('getViewportDimensions');\nconst Immutable = require('immutable');\nconst React = require('react');\nconst ReactTestRenderer = require('react-test-renderer');\n\nconst {List} = Immutable;\n\nconst rootBlock = new ContentBlockNode({\n  key: 'A',\n  text: '',\n  type: 'blockquote',\n  children: List(['B', 'C', 'D']),\n});\n\nconst contentState = ContentState.createFromBlockArray([\n  rootBlock,\n  new ContentBlockNode({\n    parent: 'A',\n    nextSibling: 'C',\n    type: 'header-three',\n    key: 'B',\n    text: 'Left',\n    children: List([]),\n  }),\n  new ContentBlockNode({\n    parent: 'A',\n    type: 'header-one',\n    prevSibling: 'B',\n    nextSibling: 'D',\n    key: 'C',\n    text: 'Middle',\n    children: List([]),\n  }),\n  new ContentBlockNode({\n    parent: 'A',\n    prevSibling: 'C',\n    type: 'header-two',\n    key: 'D',\n    text: 'Right',\n    children: List([]),\n  }),\n]);\n\nconst selectionState = new SelectionState({\n  anchorKey: 'A',\n  anchorOffset: 0,\n  focusKey: 'A',\n  focusOffset: 0,\n  isBackward: false,\n  hasFocus: false,\n});\n\nconst PROPS = {\n  block: rootBlock,\n  blockRenderMap: DefaultDraftBlockRenderMap,\n  blockRendererFn: block => null,\n  blockStyleFn: block => '',\n  contentState,\n  customStyleFn: (style, block) => null,\n  customStyleMap: {},\n  decorator: null,\n  direction: UnicodeBidiDirection.LTR,\n  editorKey: 'editor',\n  editorState: EditorState.createWithContent(contentState, null),\n  forceSelection: false,\n  offsetKey: 'A-0-0',\n  selection: selectionState,\n  tree: BlockTree.generate(contentState, rootBlock, null),\n};\n\nconst setupDomMocks = () => {\n  Style.getScrollParent.mockReturnValue(window);\n  window.scrollTo = jest.fn();\n  getElementPosition.mockReturnValue({\n    x: 0,\n    y: 600,\n    width: 500,\n    height: 16,\n  });\n  getScrollPosition.mockReturnValue({x: 0, y: 0});\n  getViewportDimensions.mockReturnValue({width: 1200, height: 800});\n};\n\nconst assertDraftEditorBlockRendering = props => {\n  const childProps = {\n    ...props,\n    editorState: EditorState.createWithContent(\n      props.contentState,\n      props.decorator,\n    ),\n  };\n\n  const blockNode = ReactTestRenderer.create(\n    <DraftEditorBlockNode {...childProps} />,\n  );\n\n  expect(\n    TestHelper.transformSnapshotProps(blockNode.toJSON()),\n  ).toMatchSnapshot();\n};\n\nbeforeEach(() => {\n  setupDomMocks();\n});\n\ntest('renders block with no children', () => {\n  const rootBlock = new ContentBlockNode({\n    key: 'A',\n    text: 'some text',\n    type: 'header-one',\n  });\n\n  const contentState = ContentState.createFromBlockArray([rootBlock]);\n\n  assertDraftEditorBlockRendering({\n    ...PROPS,\n    block: rootBlock,\n    contentState,\n    tree: BlockTree.generate(contentState, rootBlock, null),\n  });\n});\n\ntest('renders block with children', () => {\n  assertDraftEditorBlockRendering(PROPS);\n});\n\ntest('renders block with child that have wrapperElement', () => {\n  const rootBlock = new ContentBlockNode({\n    key: 'A',\n    text: '',\n    type: 'blockquote',\n    children: List(['B']),\n  });\n\n  const contentState = ContentState.createFromBlockArray([\n    rootBlock,\n    new ContentBlockNode({\n      parent: 'A',\n      key: 'B',\n      text: 'fist list item',\n      type: 'ordered-list-item',\n    }),\n  ]);\n\n  assertDraftEditorBlockRendering({\n    ...PROPS,\n    block: rootBlock,\n    contentState,\n    tree: BlockTree.generate(contentState, rootBlock, null),\n  });\n});\n\ntest('renders block with children that have same wrapperElement', () => {\n  const rootBlock = new ContentBlockNode({\n    key: 'A',\n    text: '',\n    type: 'blockquote',\n    children: List(['B', 'C']),\n  });\n\n  const contentState = ContentState.createFromBlockArray([\n    rootBlock,\n    new ContentBlockNode({\n      parent: 'A',\n      key: 'B',\n      text: 'fist list item',\n      type: 'ordered-list-item',\n      nextSibling: 'C',\n    }),\n    new ContentBlockNode({\n      parent: 'A',\n      key: 'C',\n      text: 'second list item',\n      type: 'ordered-list-item',\n      prevSibling: 'B',\n    }),\n  ]);\n\n  assertDraftEditorBlockRendering({\n    ...PROPS,\n    block: rootBlock,\n    contentState,\n    tree: BlockTree.generate(contentState, rootBlock, null),\n  });\n});\n\ntest('renders block with nested child that have same wrapperElement', () => {\n  const rootBlock = new ContentBlockNode({\n    key: 'A',\n    text: '',\n    type: 'blockquote',\n    children: List(['B']),\n  });\n\n  const contentState = ContentState.createFromBlockArray([\n    rootBlock,\n    new ContentBlockNode({\n      parent: 'A',\n      key: 'B',\n      text: '',\n      type: 'unordered-list-item',\n      children: List(['C']),\n    }),\n    new ContentBlockNode({\n      parent: 'B',\n      key: 'C',\n      text: 'deeply nested list',\n      type: 'unordered-list-item',\n    }),\n  ]);\n\n  assertDraftEditorBlockRendering({\n    ...PROPS,\n    block: rootBlock,\n    contentState,\n    tree: BlockTree.generate(contentState, rootBlock, null),\n  });\n});\n\ntest('renders block with nested child that is of different block type', () => {\n  const rootBlock = new ContentBlockNode({\n    key: 'A',\n    text: '',\n    type: 'blockquote',\n    children: List(['B']),\n  });\n\n  const contentState = ContentState.createFromBlockArray([\n    rootBlock,\n    new ContentBlockNode({\n      parent: 'A',\n      key: 'B',\n      text: 'fist list item',\n      type: 'ordered-list-item',\n      children: List(['C']),\n    }),\n    new ContentBlockNode({\n      parent: 'B',\n      key: 'C',\n      text: 'header inside list',\n      type: 'header-one',\n    }),\n  ]);\n\n  assertDraftEditorBlockRendering({\n    ...PROPS,\n    block: rootBlock,\n    contentState,\n    tree: BlockTree.generate(contentState, rootBlock, null),\n  });\n});\n\ntest('renders block with nested child that have different wrapperElement', () => {\n  const rootBlock = new ContentBlockNode({\n    key: 'A',\n    text: '',\n    type: 'blockquote',\n    children: List(['B']),\n  });\n\n  const contentState = ContentState.createFromBlockArray([\n    rootBlock,\n    new ContentBlockNode({\n      parent: 'A',\n      key: 'B',\n      text: '',\n      type: 'unordered-list-item',\n      children: List(['C']),\n    }),\n    new ContentBlockNode({\n      parent: 'B',\n      key: 'C',\n      text: 'deeply nested list',\n      type: 'ordered-list-item',\n    }),\n  ]);\n\n  assertDraftEditorBlockRendering({\n    ...PROPS,\n    block: rootBlock,\n    contentState,\n    tree: BlockTree.generate(contentState, rootBlock, null),\n  });\n});\n\ntest('renders block with nested children with decorator', () => {\n  const rootBlock = new ContentBlockNode({\n    key: 'A',\n    text: '',\n    type: 'blockquote',\n    children: List(['B']),\n  });\n\n  const contentState = ContentState.createFromBlockArray([\n    rootBlock,\n    new ContentBlockNode({\n      parent: 'A',\n      key: 'B',\n      text: 'fist list item',\n      type: 'ordered-list-item',\n      children: List(['C']),\n    }),\n    new ContentBlockNode({\n      parent: 'B',\n      key: 'C',\n      text: 'header inside list',\n      type: 'header-one',\n    }),\n  ]);\n\n  const DecoratedComponent = props => {\n    return <span className={'custom-decorated-text'}>{props.children}</span>;\n  };\n\n  const decorator = new CompositeDraftDecorator([\n    {\n      strategy: (block, callback, contentState) => {\n        if (block.getType() === 'header-one') {\n          callback(0, block.getLength());\n        }\n      },\n      component: DecoratedComponent,\n    },\n  ]);\n\n  assertDraftEditorBlockRendering({\n    ...PROPS,\n    decorator,\n    block: rootBlock,\n    contentState,\n    tree: BlockTree.generate(contentState, rootBlock, null),\n  });\n});\n\ntest('renders block with nested children with different direction', () => {\n  const rootBlock = new ContentBlockNode({\n    key: 'A',\n    text: '',\n    type: 'blockquote',\n    children: List(['B']),\n  });\n\n  const contentState = ContentState.createFromBlockArray([\n    rootBlock,\n    new ContentBlockNode({\n      parent: 'A',\n      key: 'B',\n      text: 'fist list item',\n      type: 'ordered-list-item',\n      children: List(['C']),\n    }),\n    new ContentBlockNode({\n      parent: 'B',\n      key: 'C',\n      text: 'header inside list',\n      type: 'header-one',\n    }),\n  ]);\n\n  assertDraftEditorBlockRendering({\n    ...PROPS,\n    block: rootBlock,\n    direction: UnicodeBidiDirection.RTL,\n    contentState,\n    tree: BlockTree.generate(contentState, rootBlock, null),\n  });\n});\n\ntest('renders block with nested children with custom component', () => {\n  const rootBlock = new ContentBlockNode({\n    key: 'A',\n    text: '',\n    type: 'blockquote',\n    children: List(['B']),\n  });\n\n  const contentState = ContentState.createFromBlockArray([\n    rootBlock,\n    new ContentBlockNode({\n      parent: 'A',\n      key: 'B',\n      text: 'fist list item',\n      type: 'ordered-list-item',\n      children: List(['C']),\n    }),\n    new ContentBlockNode({\n      parent: 'B',\n      key: 'C',\n      text: 'header inside list',\n      type: 'header-one',\n    }),\n  ]);\n\n  const CustomBlock = props => {\n    return <div className={'custom-header-one'}>Custom Component</div>;\n  };\n\n  assertDraftEditorBlockRendering({\n    ...PROPS,\n    block: rootBlock,\n    blockRendererFn: block => {\n      if (block.getType() === 'header-one') {\n        return {\n          component: CustomBlock,\n        };\n      }\n      return null;\n    },\n    contentState,\n    tree: BlockTree.generate(contentState, rootBlock, null),\n  });\n});\n\ntest('renders block with nested children with custom component and editable prop', () => {\n  const rootBlock = new ContentBlockNode({\n    key: 'A',\n    text: '',\n    type: 'blockquote',\n    children: List(['B']),\n  });\n\n  const contentState = ContentState.createFromBlockArray([\n    rootBlock,\n    new ContentBlockNode({\n      parent: 'A',\n      key: 'B',\n      text: 'fist list item',\n      type: 'ordered-list-item',\n      children: List(['C']),\n    }),\n    new ContentBlockNode({\n      parent: 'B',\n      key: 'C',\n      text: 'header inside list',\n      type: 'header-one',\n    }),\n  ]);\n\n  const CustomBlock = props => {\n    return (\n      <div className={'custom-header-one'}>\n        Custom Component {props.blockProps.foo}\n      </div>\n    );\n  };\n\n  assertDraftEditorBlockRendering({\n    ...PROPS,\n    block: rootBlock,\n    blockRendererFn: block => {\n      if (block.getType() === 'header-one') {\n        return {\n          component: CustomBlock,\n          editable: false,\n          props: {\n            foo: 'bar',\n          },\n        };\n      }\n      return null;\n    },\n    contentState,\n    tree: BlockTree.generate(contentState, rootBlock, null),\n  });\n});\n\ntest('renders block with nested children with blockStyleFn', () => {\n  const rootBlock = new ContentBlockNode({\n    key: 'A',\n    text: '',\n    type: 'blockquote',\n    children: List(['B']),\n  });\n\n  const contentState = ContentState.createFromBlockArray([\n    rootBlock,\n    new ContentBlockNode({\n      parent: 'A',\n      key: 'B',\n      text: 'fist list item',\n      type: 'ordered-list-item',\n      children: List(['C']),\n    }),\n    new ContentBlockNode({\n      parent: 'B',\n      key: 'C',\n      text: 'header inside list',\n      type: 'header-one',\n    }),\n  ]);\n\n  assertDraftEditorBlockRendering({\n    ...PROPS,\n    block: rootBlock,\n    blockStyleFn: block => {\n      if (block.getType() === 'header-one') {\n        return 'My-fancy-custom-class';\n      }\n      return null;\n    },\n    contentState,\n    tree: BlockTree.generate(contentState, rootBlock, null),\n  });\n});\n"
  },
  {
    "path": "src/component/contents/exploration/__tests__/DraftEditorContentsExperimental.react-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst ContentBlockNode = require('ContentBlockNode');\nconst ContentState = require('ContentState');\nconst DefaultDraftBlockRenderMap = require('DefaultDraftBlockRenderMap');\nconst DraftEditorContents = require('DraftEditorContentsExperimental.react');\nconst EditorState = require('EditorState');\nconst SelectionState = require('SelectionState');\n\nconst TestHelper = require('_DraftTestHelper');\nconst Immutable = require('immutable');\nconst React = require('react');\nconst ReactTestRenderer = require('react-test-renderer');\n\nconst {List} = Immutable;\n\nconst selectionState = new SelectionState({\n  anchorKey: 'A',\n  anchorOffset: 0,\n  focusKey: 'A',\n  focusOffset: 0,\n  isBackward: false,\n  hasFocus: true,\n});\n\nconst contentState = ContentState.createFromBlockArray([\n  new ContentBlockNode({\n    key: 'A',\n    text: 'Alpha',\n    type: 'blockquote',\n    children: List(),\n  }),\n]);\n\nconst PROPS = {\n  blockRenderMap: DefaultDraftBlockRenderMap,\n  blockRendererFn: block => null,\n  blockStyleFn: block => '',\n  contentState,\n  customStyleFn: (style, block) => null,\n  editorKey: 'editor',\n  editorState: EditorState.createWithContent(contentState),\n  selection: selectionState,\n};\n\nconst assertDraftEditorContentsRendering = props => {\n  const childProps = {\n    ...props,\n    editorState: EditorState.createWithContent(props.contentState),\n  };\n\n  const blockNode = ReactTestRenderer.create(\n    <DraftEditorContents {...childProps} />,\n  );\n\n  expect(\n    TestHelper.transformSnapshotProps(blockNode.toJSON()),\n  ).toMatchSnapshot();\n};\n\ntest('renders ContentBlockNode', () => {\n  assertDraftEditorContentsRendering(PROPS);\n});\n\ntest('renders ContentBlockNodes', () => {\n  const contentState = ContentState.createFromBlockArray([\n    new ContentBlockNode({\n      key: 'A',\n      text: '',\n      type: 'blockquote',\n      children: List(['B']),\n      nextSibling: 'D',\n    }),\n    new ContentBlockNode({\n      parent: 'A',\n      key: 'B',\n      text: 'fist list item',\n      type: 'ordered-list-item',\n      children: List(['C']),\n    }),\n    new ContentBlockNode({\n      parent: 'B',\n      key: 'C',\n      text: 'header inside list',\n      type: 'header-one',\n    }),\n    new ContentBlockNode({\n      key: 'D',\n      prevSibling: 'A',\n      text: 'header two',\n      type: 'header-two',\n    }),\n  ]);\n\n  assertDraftEditorContentsRendering({\n    ...PROPS,\n    contentState,\n  });\n});\n\ntest('renders ContentBlockNodes with root blocks that have wrapperTemplate', () => {\n  const contentState = ContentState.createFromBlockArray([\n    new ContentBlockNode({\n      key: 'A',\n      text: 'list one',\n      type: 'ordered-list-item',\n      nextSibling: 'B',\n    }),\n    new ContentBlockNode({\n      key: 'B',\n      text: 'list two',\n      type: 'ordered-list-item',\n      prevSibling: 'A',\n    }),\n  ]);\n\n  assertDraftEditorContentsRendering({\n    ...PROPS,\n    contentState,\n  });\n});\n"
  },
  {
    "path": "src/component/contents/exploration/__tests__/__snapshots__/DraftEditorBlockNode.react-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`renders block with child that have wrapperElement 1`] = `\n<blockquote\n  data-block={true}\n  data-editor=\"editor\"\n  data-offset-key=\"A-0-0\"\n>\n  <div\n    className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n    data-offset-key=\"A-0-0\"\n  >\n    <ol\n      className=\"public__DraftStyleDefault__ol\"\n      data-offset-key=\"B-0-0\"\n    >\n      <li\n        data-block={true}\n        data-editor=\"editor\"\n        data-offset-key=\"B-0-0\"\n      >\n        <div\n          className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n          data-offset-key=\"B-0-0\"\n        >\n          <span\n            data-offset-key=\"B-0-0\"\n            style={Object {}}\n          >\n            <span\n              data-text=\"true\"\n            >\n              fist list item\n            </span>\n          </span>\n        </div>\n      </li>\n    </ol>\n  </div>\n</blockquote>\n`;\n\nexports[`renders block with children 1`] = `\n<blockquote\n  data-block={true}\n  data-editor=\"editor\"\n  data-offset-key=\"A-0-0\"\n>\n  <div\n    className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n    data-offset-key=\"A-0-0\"\n  >\n    <h3\n      data-block={true}\n      data-editor=\"editor\"\n      data-offset-key=\"B-0-0\"\n    >\n      <div\n        className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n        data-offset-key=\"B-0-0\"\n      >\n        <span\n          data-offset-key=\"B-0-0\"\n          style={Object {}}\n        >\n          <span\n            data-text=\"true\"\n          >\n            Left\n          </span>\n        </span>\n      </div>\n    </h3>\n    <h1\n      data-block={true}\n      data-editor=\"editor\"\n      data-offset-key=\"C-0-0\"\n    >\n      <div\n        className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n        data-offset-key=\"C-0-0\"\n      >\n        <span\n          data-offset-key=\"C-0-0\"\n          style={Object {}}\n        >\n          <span\n            data-text=\"true\"\n          >\n            Middle\n          </span>\n        </span>\n      </div>\n    </h1>\n    <h2\n      data-block={true}\n      data-editor=\"editor\"\n      data-offset-key=\"D-0-0\"\n    >\n      <div\n        className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n        data-offset-key=\"D-0-0\"\n      >\n        <span\n          data-offset-key=\"D-0-0\"\n          style={Object {}}\n        >\n          <span\n            data-text=\"true\"\n          >\n            Right\n          </span>\n        </span>\n      </div>\n    </h2>\n  </div>\n</blockquote>\n`;\n\nexports[`renders block with children that have same wrapperElement 1`] = `\n<blockquote\n  data-block={true}\n  data-editor=\"editor\"\n  data-offset-key=\"A-0-0\"\n>\n  <div\n    className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n    data-offset-key=\"A-0-0\"\n  >\n    <ol\n      className=\"public__DraftStyleDefault__ol\"\n      data-offset-key=\"B-0-0\"\n    >\n      <li\n        data-block={true}\n        data-editor=\"editor\"\n        data-offset-key=\"B-0-0\"\n      >\n        <div\n          className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n          data-offset-key=\"B-0-0\"\n        >\n          <span\n            data-offset-key=\"B-0-0\"\n            style={Object {}}\n          >\n            <span\n              data-text=\"true\"\n            >\n              fist list item\n            </span>\n          </span>\n        </div>\n      </li>\n      <li\n        data-block={true}\n        data-editor=\"editor\"\n        data-offset-key=\"C-0-0\"\n      >\n        <div\n          className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n          data-offset-key=\"C-0-0\"\n        >\n          <span\n            data-offset-key=\"C-0-0\"\n            style={Object {}}\n          >\n            <span\n              data-text=\"true\"\n            >\n              second list item\n            </span>\n          </span>\n        </div>\n      </li>\n    </ol>\n  </div>\n</blockquote>\n`;\n\nexports[`renders block with nested child that have different wrapperElement 1`] = `\n<blockquote\n  data-block={true}\n  data-editor=\"editor\"\n  data-offset-key=\"A-0-0\"\n>\n  <div\n    className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n    data-offset-key=\"A-0-0\"\n  >\n    <ul\n      className=\"public__DraftStyleDefault__ul\"\n      data-offset-key=\"B-0-0\"\n    >\n      <li\n        data-block={true}\n        data-editor=\"editor\"\n        data-offset-key=\"B-0-0\"\n      >\n        <div\n          className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n          data-offset-key=\"B-0-0\"\n        >\n          <ol\n            className=\"public__DraftStyleDefault__ol\"\n            data-offset-key=\"C-0-0\"\n          >\n            <li\n              data-block={true}\n              data-editor=\"editor\"\n              data-offset-key=\"C-0-0\"\n            >\n              <div\n                className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n                data-offset-key=\"C-0-0\"\n              >\n                <span\n                  data-offset-key=\"C-0-0\"\n                  style={Object {}}\n                >\n                  <span\n                    data-text=\"true\"\n                  >\n                    deeply nested list\n                  </span>\n                </span>\n              </div>\n            </li>\n          </ol>\n        </div>\n      </li>\n    </ul>\n  </div>\n</blockquote>\n`;\n\nexports[`renders block with nested child that have same wrapperElement 1`] = `\n<blockquote\n  data-block={true}\n  data-editor=\"editor\"\n  data-offset-key=\"A-0-0\"\n>\n  <div\n    className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n    data-offset-key=\"A-0-0\"\n  >\n    <ul\n      className=\"public__DraftStyleDefault__ul\"\n      data-offset-key=\"B-0-0\"\n    >\n      <li\n        data-block={true}\n        data-editor=\"editor\"\n        data-offset-key=\"B-0-0\"\n      >\n        <div\n          className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n          data-offset-key=\"B-0-0\"\n        >\n          <ul\n            className=\"public__DraftStyleDefault__ul\"\n            data-offset-key=\"C-0-0\"\n          >\n            <li\n              data-block={true}\n              data-editor=\"editor\"\n              data-offset-key=\"C-0-0\"\n            >\n              <div\n                className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n                data-offset-key=\"C-0-0\"\n              >\n                <span\n                  data-offset-key=\"C-0-0\"\n                  style={Object {}}\n                >\n                  <span\n                    data-text=\"true\"\n                  >\n                    deeply nested list\n                  </span>\n                </span>\n              </div>\n            </li>\n          </ul>\n        </div>\n      </li>\n    </ul>\n  </div>\n</blockquote>\n`;\n\nexports[`renders block with nested child that is of different block type 1`] = `\n<blockquote\n  data-block={true}\n  data-editor=\"editor\"\n  data-offset-key=\"A-0-0\"\n>\n  <div\n    className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n    data-offset-key=\"A-0-0\"\n  >\n    <ol\n      className=\"public__DraftStyleDefault__ol\"\n      data-offset-key=\"B-0-0\"\n    >\n      <li\n        data-block={true}\n        data-editor=\"editor\"\n        data-offset-key=\"B-0-0\"\n      >\n        <div\n          className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n          data-offset-key=\"B-0-0\"\n        >\n          <h1\n            data-block={true}\n            data-editor=\"editor\"\n            data-offset-key=\"C-0-0\"\n          >\n            <div\n              className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n              data-offset-key=\"C-0-0\"\n            >\n              <span\n                data-offset-key=\"C-0-0\"\n                style={Object {}}\n              >\n                <span\n                  data-text=\"true\"\n                >\n                  header inside list\n                </span>\n              </span>\n            </div>\n          </h1>\n        </div>\n      </li>\n    </ol>\n  </div>\n</blockquote>\n`;\n\nexports[`renders block with nested children with blockStyleFn 1`] = `\n<blockquote\n  data-block={true}\n  data-editor=\"editor\"\n  data-offset-key=\"A-0-0\"\n>\n  <div\n    className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n    data-offset-key=\"A-0-0\"\n  >\n    <ol\n      className=\"public__DraftStyleDefault__ol\"\n      data-offset-key=\"B-0-0\"\n    >\n      <li\n        data-block={true}\n        data-editor=\"editor\"\n        data-offset-key=\"B-0-0\"\n      >\n        <div\n          className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n          data-offset-key=\"B-0-0\"\n        >\n          <h1\n            className=\"My__fancy__custom__class\"\n            data-block={true}\n            data-editor=\"editor\"\n            data-offset-key=\"C-0-0\"\n          >\n            <div\n              className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n              data-offset-key=\"C-0-0\"\n            >\n              <span\n                data-offset-key=\"C-0-0\"\n                style={Object {}}\n              >\n                <span\n                  data-text=\"true\"\n                >\n                  header inside list\n                </span>\n              </span>\n            </div>\n          </h1>\n        </div>\n      </li>\n    </ol>\n  </div>\n</blockquote>\n`;\n\nexports[`renders block with nested children with custom component 1`] = `\n<blockquote\n  data-block={true}\n  data-editor=\"editor\"\n  data-offset-key=\"A-0-0\"\n>\n  <div\n    className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n    data-offset-key=\"A-0-0\"\n  >\n    <ol\n      className=\"public__DraftStyleDefault__ol\"\n      data-offset-key=\"B-0-0\"\n    >\n      <li\n        data-block={true}\n        data-editor=\"editor\"\n        data-offset-key=\"B-0-0\"\n      >\n        <div\n          className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n          data-offset-key=\"B-0-0\"\n        >\n          <h1\n            data-block={true}\n            data-editor=\"editor\"\n            data-offset-key=\"C-0-0\"\n          >\n            <div\n              className=\"custom__header__one\"\n            >\n              Custom Component\n            </div>\n          </h1>\n        </div>\n      </li>\n    </ol>\n  </div>\n</blockquote>\n`;\n\nexports[`renders block with nested children with custom component and editable prop 1`] = `\n<blockquote\n  data-block={true}\n  data-editor=\"editor\"\n  data-offset-key=\"A-0-0\"\n>\n  <div\n    className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n    data-offset-key=\"A-0-0\"\n  >\n    <ol\n      className=\"public__DraftStyleDefault__ol\"\n      data-offset-key=\"B-0-0\"\n    >\n      <li\n        data-block={true}\n        data-editor=\"editor\"\n        data-offset-key=\"B-0-0\"\n      >\n        <div\n          className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n          data-offset-key=\"B-0-0\"\n        >\n          <h1\n            contentEditable={false}\n            data-block={true}\n            data-editor=\"editor\"\n            data-offset-key=\"C-0-0\"\n            suppressContentEditableWarning={true}\n          >\n            <div\n              className=\"custom__header__one\"\n            >\n              Custom Component \n              bar\n            </div>\n          </h1>\n        </div>\n      </li>\n    </ol>\n  </div>\n</blockquote>\n`;\n\nexports[`renders block with nested children with decorator 1`] = `\n<blockquote\n  data-block={true}\n  data-editor=\"editor\"\n  data-offset-key=\"A-0-0\"\n>\n  <div\n    className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n    data-offset-key=\"A-0-0\"\n  >\n    <ol\n      className=\"public__DraftStyleDefault__ol\"\n      data-offset-key=\"B-0-0\"\n    >\n      <li\n        data-block={true}\n        data-editor=\"editor\"\n        data-offset-key=\"B-0-0\"\n      >\n        <div\n          className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n          data-offset-key=\"B-0-0\"\n        >\n          <h1\n            data-block={true}\n            data-editor=\"editor\"\n            data-offset-key=\"C-0-0\"\n          >\n            <div\n              className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n              data-offset-key=\"C-0-0\"\n            >\n              <span\n                className=\"custom__decorated__text\"\n              >\n                <span\n                  data-offset-key=\"C-0-0\"\n                  style={Object {}}\n                >\n                  <span\n                    data-text=\"true\"\n                  >\n                    header inside list\n                  </span>\n                </span>\n              </span>\n            </div>\n          </h1>\n        </div>\n      </li>\n    </ol>\n  </div>\n</blockquote>\n`;\n\nexports[`renders block with nested children with different direction 1`] = `\n<blockquote\n  data-block={true}\n  data-editor=\"editor\"\n  data-offset-key=\"A-0-0\"\n>\n  <div\n    className=\"public__DraftStyleDefault__block public__DraftStyleDefault__rtl\"\n    data-offset-key=\"A-0-0\"\n  >\n    <ol\n      className=\"public__DraftStyleDefault__ol\"\n      data-offset-key=\"B-0-0\"\n    >\n      <li\n        data-block={true}\n        data-editor=\"editor\"\n        data-offset-key=\"B-0-0\"\n      >\n        <div\n          className=\"public__DraftStyleDefault__block public__DraftStyleDefault__rtl\"\n          data-offset-key=\"B-0-0\"\n        >\n          <h1\n            data-block={true}\n            data-editor=\"editor\"\n            data-offset-key=\"C-0-0\"\n          >\n            <div\n              className=\"public__DraftStyleDefault__block public__DraftStyleDefault__rtl\"\n              data-offset-key=\"C-0-0\"\n            >\n              <span\n                data-offset-key=\"C-0-0\"\n                style={Object {}}\n              >\n                <span\n                  data-text=\"true\"\n                >\n                  header inside list\n                </span>\n              </span>\n            </div>\n          </h1>\n        </div>\n      </li>\n    </ol>\n  </div>\n</blockquote>\n`;\n\nexports[`renders block with no children 1`] = `\n<h1\n  data-block={true}\n  data-editor=\"editor\"\n  data-offset-key=\"A-0-0\"\n>\n  <div\n    className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n    data-offset-key=\"A-0-0\"\n  >\n    <span\n      data-offset-key=\"A-0-0\"\n      style={Object {}}\n    >\n      <span\n        data-text=\"true\"\n      >\n        some text\n      </span>\n    </span>\n  </div>\n</h1>\n`;\n"
  },
  {
    "path": "src/component/contents/exploration/__tests__/__snapshots__/DraftEditorContentsExperimental.react-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`renders ContentBlockNode 1`] = `\n<div\n  data-contents=\"true\"\n>\n  <blockquote\n    data-block={true}\n    data-editor=\"editor\"\n    data-offset-key=\"A-0-0\"\n  >\n    <div\n      className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n      data-offset-key=\"A-0-0\"\n    >\n      <span\n        data-offset-key=\"A-0-0\"\n        style={Object {}}\n      >\n        <span\n          data-text=\"true\"\n        >\n          Alpha\n        </span>\n      </span>\n    </div>\n  </blockquote>\n</div>\n`;\n\nexports[`renders ContentBlockNodes 1`] = `\n<div\n  data-contents=\"true\"\n>\n  <blockquote\n    data-block={true}\n    data-editor=\"editor\"\n    data-offset-key=\"A-0-0\"\n  >\n    <div\n      className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n      data-offset-key=\"A-0-0\"\n    >\n      <ol\n        className=\"public__DraftStyleDefault__ol\"\n        data-offset-key=\"B-0-0\"\n      >\n        <li\n          data-block={true}\n          data-editor=\"editor\"\n          data-offset-key=\"B-0-0\"\n        >\n          <div\n            className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n            data-offset-key=\"B-0-0\"\n          >\n            <h1\n              data-block={true}\n              data-editor=\"editor\"\n              data-offset-key=\"C-0-0\"\n            >\n              <div\n                className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n                data-offset-key=\"C-0-0\"\n              >\n                <span\n                  data-offset-key=\"C-0-0\"\n                  style={Object {}}\n                >\n                  <span\n                    data-text=\"true\"\n                  >\n                    header inside list\n                  </span>\n                </span>\n              </div>\n            </h1>\n          </div>\n        </li>\n      </ol>\n    </div>\n  </blockquote>\n  <h2\n    data-block={true}\n    data-editor=\"editor\"\n    data-offset-key=\"D-0-0\"\n  >\n    <div\n      className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n      data-offset-key=\"D-0-0\"\n    >\n      <span\n        data-offset-key=\"D-0-0\"\n        style={Object {}}\n      >\n        <span\n          data-text=\"true\"\n        >\n          header two\n        </span>\n      </span>\n    </div>\n  </h2>\n</div>\n`;\n\nexports[`renders ContentBlockNodes with root blocks that have wrapperTemplate 1`] = `\n<div\n  data-contents=\"true\"\n>\n  <ol\n    className=\"public__DraftStyleDefault__ol\"\n    data-offset-key=\"A-0-0\"\n  >\n    <li\n      data-block={true}\n      data-editor=\"editor\"\n      data-offset-key=\"A-0-0\"\n    >\n      <div\n        className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n        data-offset-key=\"A-0-0\"\n      >\n        <span\n          data-offset-key=\"A-0-0\"\n          style={Object {}}\n        >\n          <span\n            data-text=\"true\"\n          >\n            list one\n          </span>\n        </span>\n      </div>\n    </li>\n    <li\n      data-block={true}\n      data-editor=\"editor\"\n      data-offset-key=\"B-0-0\"\n    >\n      <div\n        className=\"public__DraftStyleDefault__block public__DraftStyleDefault__ltr\"\n        data-offset-key=\"B-0-0\"\n      >\n        <span\n          data-offset-key=\"B-0-0\"\n          style={Object {}}\n        >\n          <span\n            data-text=\"true\"\n          >\n            list two\n          </span>\n        </span>\n      </div>\n    </li>\n  </ol>\n</div>\n`;\n"
  },
  {
    "path": "src/component/handlers/DraftEditorModes.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nexport type DraftEditorModes =\n  /**\n   * `edit` is the most common mode for text entry. This includes most typing,\n   * deletion, cut/copy/paste, and other behaviors.\n   */\n  | 'edit'\n\n  /**\n   * `composite` mode handles IME text entry.\n   */\n  | 'composite'\n\n  /**\n   * `drag` mode handles editor behavior while a drag event is occurring.\n   */\n  | 'drag'\n\n  /**\n   * `cut` mode allows us to effectively ignore all edit behaviors while the`\n   * browser performs a native `cut` operation on the DOM.\n   */\n  | 'cut'\n\n  /**\n   * `render` mode is the normal \"null\" mode, during which no edit behavior is\n   * expected or observed.\n   */\n  | 'render';\n"
  },
  {
    "path": "src/component/handlers/composition/DOMObserver.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst UserAgent = require('UserAgent');\n\nconst findAncestorOffsetKey = require('findAncestorOffsetKey');\nconst getWindowForNode = require('getWindowForNode');\nconst Immutable = require('immutable');\nconst invariant = require('invariant');\nconst nullthrows = require('nullthrows');\n\nconst {Map} = Immutable;\n\ntype MutationRecordT =\n  | MutationRecord\n  | {type: 'characterData', target: Node, removedNodes?: void};\n\n// Heavily based on Prosemirror's DOMObserver https://github.com/ProseMirror/prosemirror-view/blob/master/src/domobserver.js\n\nconst DOM_OBSERVER_OPTIONS = {\n  subtree: true,\n  characterData: true,\n  childList: true,\n  characterDataOldValue: false,\n  attributes: false,\n};\n// IE11 has very broken mutation observers, so we also listen to DOMCharacterDataModified\nconst USE_CHAR_DATA = UserAgent.isBrowser('IE <= 11');\n\nclass DOMObserver {\n  observer: ?MutationObserver;\n  container: HTMLElement;\n  mutations: Map<string, string>;\n  onCharData: ?({\n    target: EventTarget,\n    type: string,\n    ...\n  }) => void;\n\n  constructor(container: HTMLElement) {\n    this.container = container;\n    this.mutations = Map();\n    const containerWindow = getWindowForNode(container);\n    const MutationObserver = containerWindow.MutationObserver;\n    if (MutationObserver && !USE_CHAR_DATA) {\n      this.observer = new MutationObserver(mutations =>\n        this.registerMutations(mutations),\n      );\n    } else {\n      this.onCharData = e => {\n        invariant(\n          e.target instanceof Node,\n          'Expected target to be an instance of Node',\n        );\n        this.registerMutation({\n          type: 'characterData',\n          target: e.target,\n        });\n      };\n    }\n  }\n\n  start(): void {\n    if (this.observer) {\n      this.observer.observe(this.container, DOM_OBSERVER_OPTIONS);\n    } else {\n      /* $FlowFixMe[incompatible-call] (>=0.68.0 site=www,mobile) This event\n       * type is not defined by Flow's standard library */\n      this.container.addEventListener(\n        'DOMCharacterDataModified',\n        this.onCharData,\n      );\n    }\n  }\n\n  stopAndFlushMutations(): Map<string, string> {\n    const {observer} = this;\n    if (observer) {\n      this.registerMutations(observer.takeRecords());\n      observer.disconnect();\n    } else {\n      /* $FlowFixMe[incompatible-call] (>=0.68.0 site=www,mobile) This event\n       * type is not defined by Flow's standard library */\n      this.container.removeEventListener(\n        'DOMCharacterDataModified',\n        this.onCharData,\n      );\n    }\n    const mutations = this.mutations;\n    this.mutations = Map();\n    return mutations;\n  }\n\n  registerMutations(mutations: Array<MutationRecord>): void {\n    for (let i = 0; i < mutations.length; i++) {\n      this.registerMutation(mutations[i]);\n    }\n  }\n\n  getMutationTextContent(mutation: MutationRecordT): ?string {\n    const {type, target, removedNodes} = mutation;\n    if (type === 'characterData') {\n      // When `textContent` is '', there is a race condition that makes\n      // getting the offsetKey from the target not possible.\n      // These events are also followed by a `childList`, which is the one\n      // we are able to retrieve the offsetKey and apply the '' text.\n      if (target.textContent !== '') {\n        // IE 11 considers the enter keypress that concludes the composition\n        // as an input char. This strips that newline character so the draft\n        // state does not receive spurious newlines.\n        if (USE_CHAR_DATA) {\n          return target.textContent.replace('\\n', '');\n        }\n        return target.textContent;\n      }\n    } else if (type === 'childList') {\n      if (removedNodes && removedNodes.length) {\n        // `characterData` events won't happen or are ignored when\n        // removing the last character of a leaf node, what happens\n        // instead is a `childList` event with a `removedNodes` array.\n        // For this case the textContent should be '' and\n        // `DraftModifier.replaceText` will make sure the content is\n        // updated properly.\n        return '';\n      } else if (target.textContent !== '') {\n        // Typing Chinese in an empty block in MS Edge results in a\n        // `childList` event with non-empty textContent.\n        // See https://github.com/facebook/draft-js/issues/2082\n        return target.textContent;\n      }\n    }\n    return null;\n  }\n\n  registerMutation(mutation: MutationRecordT): void {\n    const textContent = this.getMutationTextContent(mutation);\n    if (textContent != null) {\n      const offsetKey = nullthrows(findAncestorOffsetKey(mutation.target));\n      this.mutations = this.mutations.set(offsetKey, textContent);\n    }\n  }\n}\n\nmodule.exports = DOMObserver;\n"
  },
  {
    "path": "src/component/handlers/composition/DraftEditorCompositionHandler.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type DraftEditor from 'DraftEditor.react';\n\nconst DOMObserver = require('DOMObserver');\nconst DraftModifier = require('DraftModifier');\nconst DraftOffsetKey = require('DraftOffsetKey');\nconst EditorState = require('EditorState');\nconst Keys = require('Keys');\nconst UserAgent = require('UserAgent');\n\nconst editOnSelect = require('editOnSelect');\nconst getContentEditableContainer = require('getContentEditableContainer');\nconst getDraftEditorSelection = require('getDraftEditorSelection');\nconst getEntityKeyForSelection = require('getEntityKeyForSelection');\nconst nullthrows = require('nullthrows');\n\nconst isIE = UserAgent.isBrowser('IE');\n\n/**\n * Millisecond delay to allow `compositionstart` to fire again upon\n * `compositionend`.\n *\n * This is used for Korean input to ensure that typing can continue without\n * the editor trying to render too quickly. More specifically, Safari 7.1+\n * triggers `compositionstart` a little slower than Chrome/FF, which\n * leads to composed characters being resolved and re-render occurring\n * sooner than we want.\n */\nconst RESOLVE_DELAY = 20;\n\n/**\n * A handful of variables used to track the current composition and its\n * resolution status. These exist at the module level because it is not\n * possible to have compositions occurring in multiple editors simultaneously,\n * and it simplifies state management with respect to the DraftEditor component.\n */\nlet resolved = false;\nlet stillComposing = false;\nlet domObserver = null;\n\nfunction startDOMObserver(editor: DraftEditor) {\n  if (!domObserver) {\n    domObserver = new DOMObserver(getContentEditableContainer(editor));\n    domObserver.start();\n  }\n}\n\nconst DraftEditorCompositionHandler = {\n  /**\n   * A `compositionstart` event has fired while we're still in composition\n   * mode. Continue the current composition session to prevent a re-render.\n   */\n  onCompositionStart(editor: DraftEditor): void {\n    stillComposing = true;\n    startDOMObserver(editor);\n  },\n\n  /**\n   * Attempt to end the current composition session.\n   *\n   * Defer handling because browser will still insert the chars into active\n   * element after `compositionend`. If a `compositionstart` event fires\n   * before `resolveComposition` executes, our composition session will\n   * continue.\n   *\n   * The `resolved` flag is useful because certain IME interfaces fire the\n   * `compositionend` event multiple times, thus queueing up multiple attempts\n   * at handling the composition. Since handling the same composition event\n   * twice could break the DOM, we only use the first event. Example: Arabic\n   * Google Input Tools on Windows 8.1 fires `compositionend` three times.\n   */\n  onCompositionEnd(editor: DraftEditor): void {\n    resolved = false;\n    stillComposing = false;\n    setTimeout(() => {\n      if (!resolved) {\n        DraftEditorCompositionHandler.resolveComposition(editor);\n      }\n    }, RESOLVE_DELAY);\n  },\n\n  onSelect: editOnSelect,\n\n  /**\n   * In Safari, keydown events may fire when committing compositions. If\n   * the arrow keys are used to commit, prevent default so that the cursor\n   * doesn't move, otherwise it will jump back noticeably on re-render.\n   */\n  onKeyDown(editor: DraftEditor, e: SyntheticKeyboardEvent<>): void {\n    if (!stillComposing) {\n      // This check was added in D23734060. Seemingly, we should be checking\n      // to see if the resolved flag is false here, otherwise the below\n      // comment doesn't make sense. With this change, it should prevent\n      // over-firing the resolveComposition() method, which might help fix\n      // some existing IME issues.\n      if (!resolved) {\n        // If a keydown event is received after compositionend but before the\n        // 20ms timer expires (ex: type option-E then backspace, or type A then\n        // backspace in 2-Set Korean), we should immediately resolve the\n        // composition and reinterpret the key press in edit mode.\n        DraftEditorCompositionHandler.resolveComposition(editor);\n      }\n      editor._onKeyDown(e);\n      return;\n    }\n    if (e.which === Keys.RIGHT || e.which === Keys.LEFT) {\n      e.preventDefault();\n    }\n  },\n\n  /**\n   * Keypress events may fire when committing compositions. In Firefox,\n   * pressing RETURN commits the composition and inserts extra newline\n   * characters that we do not want. `preventDefault` allows the composition\n   * to be committed while preventing the extra characters.\n   */\n  onKeyPress(_editor: DraftEditor, e: SyntheticKeyboardEvent<>): void {\n    if (e.which === Keys.RETURN) {\n      e.preventDefault();\n    }\n  },\n\n  /**\n   * Attempt to insert composed characters into the document.\n   *\n   * If we are still in a composition session, do nothing. Otherwise, insert\n   * the characters into the document and terminate the composition session.\n   *\n   * If no characters were composed -- for instance, the user\n   * deleted all composed characters and committed nothing new --\n   * force a re-render. We also re-render when the composition occurs\n   * at the beginning of a leaf, to ensure that if the browser has\n   * created a new text node for the composition, we will discard it.\n   *\n   * Resetting innerHTML will move focus to the beginning of the editor,\n   * so we update to force it back to the correct place.\n   */\n  resolveComposition(editor: DraftEditor): void {\n    if (stillComposing) {\n      return;\n    }\n\n    const lastEditorState = editor._latestEditorState;\n    const mutations = nullthrows(domObserver).stopAndFlushMutations();\n    domObserver = null;\n    resolved = true;\n\n    let editorState = EditorState.set(lastEditorState, {\n      inCompositionMode: false,\n    });\n\n    editor.exitCurrentMode();\n\n    if (!mutations.size) {\n      editor.update(editorState);\n      return;\n    }\n\n    // TODO, check if Facebook still needs this flag or if it could be removed.\n    // Since there can be multiple mutations providing a `composedChars` doesn't\n    // apply well on this new model.\n    // if (\n    //   gkx('draft_handlebeforeinput_composed_text') &&\n    //   editor.props.handleBeforeInput &&\n    //   isEventHandled(\n    //     editor.props.handleBeforeInput(\n    //       composedChars,\n    //       editorState,\n    //       event.timeStamp,\n    //     ),\n    //   )\n    // ) {\n    //   return;\n    // }\n\n    let contentState = editorState.getCurrentContent();\n    mutations.forEach((composedChars, offsetKey) => {\n      const {blockKey, decoratorKey, leafKey} =\n        DraftOffsetKey.decode(offsetKey);\n\n      const {start, end} = editorState\n        .getBlockTree(blockKey)\n        .getIn([decoratorKey, 'leaves', leafKey]);\n\n      const replacementRange = editorState.getSelection().merge({\n        anchorKey: blockKey,\n        focusKey: blockKey,\n        anchorOffset: start,\n        focusOffset: end,\n        isBackward: false,\n      });\n\n      const entityKey = getEntityKeyForSelection(\n        contentState,\n        replacementRange,\n      );\n      const currentStyle = contentState\n        .getBlockForKey(blockKey)\n        .getInlineStyleAt(start);\n\n      contentState = DraftModifier.replaceText(\n        contentState,\n        replacementRange,\n        composedChars,\n        currentStyle,\n        entityKey,\n      );\n      // We need to update the editorState so the leaf node ranges are properly\n      // updated and multiple mutations are correctly applied.\n      editorState = EditorState.set(editorState, {\n        currentContent: contentState,\n      });\n    });\n\n    // When we apply the text changes to the ContentState, the selection always\n    // goes to the end of the field, but it should just stay where it is\n    // after compositionEnd. We also apply this to the last editor state, rather\n    // than the new editor state in order to avoid problems that might come from\n    // race conditions around calculating ranges from mutations when processing\n    // the mutations above. If the ranges are off, for example, using mentions\n    // in IME mode, then the selection will move the cursor to an invalid range.\n    // See D23905960 for more context:\n    const documentSelection = getDraftEditorSelection(\n      lastEditorState,\n      getContentEditableContainer(editor),\n    );\n    const compositionEndSelectionState = documentSelection.selectionState;\n\n    editor.restoreEditorDOM();\n\n    // See:\n    // - https://github.com/facebook/draft-js/issues/2093\n    // - https://github.com/facebook/draft-js/pull/2094\n    // Apply this fix only in IE for now. We can test it in\n    // other browsers in the future to ensure no regressions\n    const editorStateWithUpdatedSelection = isIE\n      ? EditorState.forceSelection(editorState, compositionEndSelectionState)\n      : EditorState.acceptSelection(editorState, compositionEndSelectionState);\n\n    editor.update(\n      EditorState.push(\n        editorStateWithUpdatedSelection,\n        contentState,\n        'insert-characters',\n      ),\n    );\n  },\n};\n\nmodule.exports = DraftEditorCompositionHandler;\n"
  },
  {
    "path": "src/component/handlers/composition/__tests__/DraftEditorCompostionHandler-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type DraftEditor from 'DraftEditor.react';\n\nconst ContentBlock = require('ContentBlock');\nconst ContentState = require('ContentState');\nconst EditorState = require('EditorState');\nconst SelectionState = require('SelectionState');\n\nconst convertFromHTMLToContentBlocks = require('convertFromHTMLToContentBlocks');\nconst editOnCompositionStart = require('editOnCompositionStart');\nconst {Map} = require('immutable');\n\n// DraftEditorComposition uses timers to detect duplicate `compositionend`\n// events.\njest.useFakeTimers();\n\njest.mock('DOMObserver', () => {\n  function DOMObserver() {}\n  // $FlowFixMe[prop-missing]\n  DOMObserver.prototype.start = jest.fn();\n  // $FlowFixMe[prop-missing]\n  DOMObserver.prototype.stopAndFlushMutations = jest\n    .fn()\n    .mockReturnValue(Map({}));\n  return DOMObserver;\n});\njest.mock('getContentEditableContainer');\njest.mock('getDraftEditorSelection', () => {\n  return jest.fn().mockReturnValue({\n    selectionState: SelectionState.createEmpty('anchor-key'),\n  });\n});\n\n// The DraftEditorCompositionHandler contains some global state\n// (internally used to make the code simpler given that only one\n// composition can be happening at a given time), so to avoid\n// false-positive failures stemming from test cases putting\n// the module in a bad state we forcibly reload it each test.\nlet compositionHandler = null;\n// Initialization of mock editor component that will be used for all tests\nlet editor: {\n  _latestEditorState: EditorState,\n  _onCompositionStart: (editor: DraftEditor) => void,\n  _onKeyDown: JestMockFn<$FlowFixMe, $FlowFixMe>,\n  exitCurrentMode: JestMockFn<$FlowFixMe, $FlowFixMe>,\n  restoreEditorDOM: JestMockFn<$FlowFixMe, $FlowFixMe>,\n  setMode: JestMockFn<$FlowFixMe, $FlowFixMe>,\n  update: JestMockFn<$FlowFixMe, $FlowFixMe>,\n};\n\nfunction getEditorState(\n  blocks:\n    | $TEMPORARY$object<{blockkey0: string}>\n    | $TEMPORARY$object<{\n        blockkey0: $TEMPORARY$string<'react'>,\n        blockkey1: $TEMPORARY$string<'draft'>,\n      }>,\n) {\n  const contentBlocks = Object.keys(blocks).map(blockKey => {\n    return new ContentBlock({\n      key: blockKey,\n      text: blocks[String(blockKey)],\n    });\n  });\n  return EditorState.createWithContent(\n    ContentState.createFromBlockArray(contentBlocks),\n  );\n}\n\nfunction getEditorStateFromHTML(html: string) {\n  const blocksFromHTML = convertFromHTMLToContentBlocks(html);\n  const state =\n    blocksFromHTML != null\n      ? ContentState.createFromBlockArray(\n          blocksFromHTML.contentBlocks || [],\n          blocksFromHTML.entityMap,\n        )\n      : ContentState.createFromText('');\n  return EditorState.createWithContent(state);\n}\n\nfunction editorTextContent() {\n  return editor._latestEditorState.getCurrentContent().getPlainText();\n}\n\nfunction withGlobalGetSelectionAs(\n  getSelectionValue: $TEMPORARY$object<{...}>,\n  callback: () => void,\n) {\n  const oldGetSelection = global.getSelection;\n  try {\n    global.getSelection = () => getSelectionValue;\n    callback();\n  } finally {\n    global.getSelection = oldGetSelection;\n  }\n}\n\nbeforeEach(() => {\n  jest.resetModules();\n  compositionHandler = require('DraftEditorCompositionHandler');\n  editor = {\n    _latestEditorState: EditorState.createEmpty(),\n    _onCompositionStart: compositionHandler.onCompositionStart,\n    _onKeyDown: jest.fn(),\n    setMode: jest.fn(),\n    restoreEditorDOM: jest.fn(),\n    exitCurrentMode: jest.fn(),\n    update: jest.fn(state => (editor._latestEditorState = state)),\n  };\n});\n\ntest('isInCompositionMode is properly updated on composition events', () => {\n  // `inCompositionMode` is updated inside editOnCompositionStart,\n  // which is why we can't just call compositionHandler.onCompositionStart.\n  // $FlowExpectedError[incompatible-call]\n  editOnCompositionStart(editor, {});\n  expect(editor.setMode).toHaveBeenLastCalledWith('composite');\n  expect(editor._latestEditorState.isInCompositionMode()).toBe(true);\n  // $FlowExpectedError[incompatible-use]\n  // $FlowExpectedError[incompatible-call]\n  compositionHandler.onCompositionEnd(editor);\n  jest.runAllTimers();\n  expect(editor._latestEditorState.isInCompositionMode()).toBe(false);\n  expect(editor.exitCurrentMode).toHaveBeenCalled();\n});\n\ntest('Can handle a single mutation', () => {\n  withGlobalGetSelectionAs({}, () => {\n    editor._latestEditorState = getEditorState({blockkey0: ''});\n    const mutations = Map({'blockkey0-0-0': '\\u79c1'});\n    // $FlowFixMe[method-unbinding] added when improving typing for this parameters\n    require('DOMObserver').prototype.stopAndFlushMutations.mockReturnValue(\n      mutations,\n    );\n    // $FlowExpectedError[incompatible-use]\n    // $FlowExpectedError[incompatible-call]\n    compositionHandler.onCompositionStart(editor);\n    // $FlowExpectedError[incompatible-use]\n    // $FlowExpectedError[incompatible-call]\n    compositionHandler.onCompositionEnd(editor);\n    jest.runAllTimers();\n\n    expect(editorTextContent()).toBe('\\u79c1');\n  });\n});\n\ntest('Can handle mutations in multiple blocks', () => {\n  withGlobalGetSelectionAs({}, () => {\n    editor._latestEditorState = getEditorState({\n      blockkey0: 'react',\n      blockkey1: 'draft',\n    });\n    const mutations = Map({\n      'blockkey0-0-0': 'reactjs',\n      'blockkey1-0-0': 'draftjs',\n    });\n    // $FlowFixMe[method-unbinding] added when improving typing for this parameters\n    require('DOMObserver').prototype.stopAndFlushMutations.mockReturnValue(\n      mutations,\n    );\n    // $FlowExpectedError[incompatible-use]\n    // $FlowExpectedError[incompatible-call]\n    compositionHandler.onCompositionStart(editor);\n    // $FlowExpectedError[incompatible-use]\n    // $FlowExpectedError[incompatible-call]\n    compositionHandler.onCompositionEnd(editor);\n    jest.runAllTimers();\n\n    expect(editorTextContent()).toBe('reactjs\\ndraftjs');\n  });\n});\n\ntest('Can handle mutations in the same block in multiple leaf nodes', () => {\n  withGlobalGetSelectionAs({}, () => {\n    const editorState = (editor._latestEditorState = getEditorStateFromHTML(\n      '<div>react <b>draft</b> graphql</div>',\n    ));\n    const blockKey = editorState\n      .getCurrentContent()\n      .getBlockMap()\n      .first()\n      .getKey();\n    const mutations = Map<_, mixed>({\n      [`${blockKey}-0-0`]: 'reacta ',\n      [`${blockKey}-0-1`]: 'draftbb',\n      [`${blockKey}-0-2`]: ' graphqlccc',\n    });\n    // $FlowFixMe[method-unbinding] added when improving typing for this parameters\n    require('DOMObserver').prototype.stopAndFlushMutations.mockReturnValue(\n      mutations,\n    );\n    // $FlowExpectedError[incompatible-use]\n    // $FlowExpectedError[incompatible-call]\n    compositionHandler.onCompositionStart(editor);\n    // $FlowExpectedError[incompatible-use]\n    // $FlowExpectedError[incompatible-call]\n    compositionHandler.onCompositionEnd(editor);\n    jest.runAllTimers();\n\n    expect(editorTextContent()).toBe('reacta draftbb graphqlccc');\n  });\n});\n"
  },
  {
    "path": "src/component/handlers/drag/DraftEditorDragHandler.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type DraftEditor from 'DraftEditor.react';\nimport type SelectionState from 'SelectionState';\n\nconst DataTransfer = require('DataTransfer');\nconst DraftModifier = require('DraftModifier');\nconst EditorState = require('EditorState');\n\nconst findAncestorOffsetKey = require('findAncestorOffsetKey');\nconst getCorrectDocumentFromNode = require('getCorrectDocumentFromNode');\nconst getTextContentFromFiles = require('getTextContentFromFiles');\nconst getUpdatedSelectionState = require('getUpdatedSelectionState');\nconst getWindowForNode = require('getWindowForNode');\nconst isEventHandled = require('isEventHandled');\nconst nullthrows = require('nullthrows');\n\n/**\n * Get a SelectionState for the supplied mouse event.\n */\nfunction getSelectionForEvent(\n  event: Object,\n  editorState: EditorState,\n): ?SelectionState {\n  let node: ?Node = null;\n  let offset: ?number = null;\n\n  const eventTargetDocument = getCorrectDocumentFromNode(event.currentTarget);\n  /* $FlowFixMe[prop-missing] (>=0.68.0 site=www,mobile) This comment\n   * suppresses an error found when Flow v0.68 was deployed. To see the error\n   * delete this comment and run Flow. */\n  if (typeof eventTargetDocument.caretRangeFromPoint === 'function') {\n    /* $FlowFixMe[incompatible-use] (>=0.68.0 site=www,mobile) This comment\n     * suppresses an error found when Flow v0.68 was deployed. To see the error\n     * delete this comment and run Flow. */\n    const dropRange = eventTargetDocument.caretRangeFromPoint(event.x, event.y);\n    node = dropRange.startContainer;\n    offset = dropRange.startOffset;\n  } else if (event.rangeParent) {\n    node = event.rangeParent;\n    offset = event.rangeOffset;\n  } else {\n    return null;\n  }\n\n  node = nullthrows(node);\n  offset = nullthrows(offset);\n  const offsetKey = nullthrows(findAncestorOffsetKey(node));\n\n  return getUpdatedSelectionState(\n    editorState,\n    offsetKey,\n    offset,\n    offsetKey,\n    offset,\n  );\n}\n\nconst DraftEditorDragHandler = {\n  /**\n   * Drag originating from input terminated.\n   */\n  onDragEnd(editor: DraftEditor): void {\n    editor.exitCurrentMode();\n    endDrag(editor);\n  },\n\n  /**\n   * Handle data being dropped.\n   */\n  onDrop(editor: DraftEditor, e: Object): void {\n    const data = new DataTransfer(e.nativeEvent.dataTransfer);\n\n    const editorState: EditorState = editor._latestEditorState;\n    const dropSelection: ?SelectionState = getSelectionForEvent(\n      e.nativeEvent,\n      editorState,\n    );\n\n    e.preventDefault();\n    editor._dragCount = 0;\n    editor.exitCurrentMode();\n\n    if (dropSelection == null) {\n      return;\n    }\n\n    const files: Array<Blob> = (data.getFiles(): any);\n    if (files.length > 0) {\n      if (\n        editor.props.handleDroppedFiles &&\n        isEventHandled(editor.props.handleDroppedFiles(dropSelection, files))\n      ) {\n        return;\n      }\n\n      /* $FlowFixMe[incompatible-call] This comment suppresses an error found\n       * DataTransfer was typed. getFiles() returns an array of <Files extends\n       * Blob>, not Blob */\n      getTextContentFromFiles(files, fileText => {\n        fileText &&\n          editor.update(\n            insertTextAtSelection(editorState, dropSelection, fileText),\n          );\n      });\n      return;\n    }\n\n    const dragType = editor._internalDrag ? 'internal' : 'external';\n    if (\n      editor.props.handleDrop &&\n      isEventHandled(editor.props.handleDrop(dropSelection, data, dragType))\n    ) {\n      // handled\n    } else if (editor._internalDrag) {\n      editor.update(moveText(editorState, dropSelection));\n    } else {\n      editor.update(\n        insertTextAtSelection(\n          editorState,\n          dropSelection,\n          (data.getText(): any),\n        ),\n      );\n    }\n    endDrag(editor);\n  },\n};\n\nfunction endDrag(editor: DraftEditor) {\n  editor._internalDrag = false;\n\n  // Fix issue #1383\n  // Prior to React v16.5.0 onDrop breaks onSelect event:\n  // https://github.com/facebook/react/issues/11379.\n  // Dispatching a mouseup event on DOM node will make it go back to normal.\n  const editorNode = editor.editorContainer;\n  if (editorNode) {\n    const mouseUpEvent = new MouseEvent('mouseup', {\n      view: getWindowForNode(editorNode),\n      bubbles: true,\n      cancelable: true,\n    });\n    editorNode.dispatchEvent(mouseUpEvent);\n  }\n}\n\nfunction moveText(\n  editorState: EditorState,\n  targetSelection: SelectionState,\n): EditorState {\n  const newContentState = DraftModifier.moveText(\n    editorState.getCurrentContent(),\n    editorState.getSelection(),\n    targetSelection,\n  );\n  return EditorState.push(editorState, newContentState, 'insert-fragment');\n}\n\n/**\n * Insert text at a specified selection.\n */\nfunction insertTextAtSelection(\n  editorState: EditorState,\n  selection: SelectionState,\n  text: string,\n): EditorState {\n  const newContentState = DraftModifier.insertText(\n    editorState.getCurrentContent(),\n    selection,\n    text,\n    editorState.getCurrentInlineStyle(),\n  );\n  return EditorState.push(editorState, newContentState, 'insert-fragment');\n}\n\nmodule.exports = DraftEditorDragHandler;\n"
  },
  {
    "path": "src/component/handlers/edit/DraftEditorEditHandler.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type DraftEditor from 'DraftEditor.react';\n\nconst UserAgent = require('UserAgent');\n\nconst onBeforeInput = require('editOnBeforeInput');\nconst onBlur = require('editOnBlur');\nconst onCompositionStart = require('editOnCompositionStart');\nconst onCopy = require('editOnCopy');\nconst onCut = require('editOnCut');\nconst onDragOver = require('editOnDragOver');\nconst onDragStart = require('editOnDragStart');\nconst onFocus = require('editOnFocus');\nconst onInput = require('editOnInput');\nconst onKeyDown = require('editOnKeyDown');\nconst onPaste = require('editOnPaste');\nconst onSelect = require('editOnSelect');\n\nconst isChrome = UserAgent.isBrowser('Chrome');\nconst isFirefox = UserAgent.isBrowser('Firefox');\n\nconst selectionHandler: (e: DraftEditor) => void =\n  isChrome || isFirefox ? onSelect : (e: DraftEditor) => {};\n\nconst DraftEditorEditHandler = {\n  onBeforeInput,\n  onBlur,\n  onCompositionStart,\n  onCopy,\n  onCut,\n  onDragOver,\n  onDragStart,\n  onFocus,\n  onInput,\n  onKeyDown,\n  onPaste,\n  onSelect,\n  // In certain cases, contenteditable on chrome does not fire the onSelect\n  // event, causing problems with cursor positioning. Therefore, the selection\n  // state update handler is added to more events to ensure that the selection\n  // state is always synced with the actual cursor positions.\n  onMouseUp: selectionHandler,\n  onKeyUp: selectionHandler,\n};\n\nmodule.exports = DraftEditorEditHandler;\n"
  },
  {
    "path": "src/component/handlers/edit/__tests__/__snapshots__/editOnBeforeInput-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`editor is updated with new text if it does not match current selection 1`] = `\nImmutable.Record {\n  \"entityMap\": Object {\n    \"__add\": [Function],\n    \"__create\": [Function],\n    \"__get\": [Function],\n    \"__getAll\": [Function],\n    \"__getLastCreatedEntityKey\": [Function],\n    \"__loadWithEntities\": [Function],\n    \"__mergeData\": [Function],\n    \"__replaceData\": [Function],\n    \"get\": [Function],\n    \"last\": [Function],\n    \"set\": [Function],\n  },\n  \"blockMap\": Immutable.OrderedMap {\n    \"a\": Immutable.Record {\n      \"key\": \"a\",\n      \"type\": \"unstyled\",\n      \"text\": \"Orsenal\",\n      \"characterList\": Immutable.List [\n        Immutable.Record {\n          \"style\": Immutable.OrderedSet [],\n          \"entity\": null,\n        },\n        Immutable.Record {\n          \"style\": Immutable.OrderedSet [],\n          \"entity\": null,\n        },\n        Immutable.Record {\n          \"style\": Immutable.OrderedSet [],\n          \"entity\": null,\n        },\n        Immutable.Record {\n          \"style\": Immutable.OrderedSet [],\n          \"entity\": null,\n        },\n        Immutable.Record {\n          \"style\": Immutable.OrderedSet [],\n          \"entity\": null,\n        },\n        Immutable.Record {\n          \"style\": Immutable.OrderedSet [],\n          \"entity\": null,\n        },\n        Immutable.Record {\n          \"style\": Immutable.OrderedSet [],\n          \"entity\": null,\n        },\n      ],\n      \"depth\": 0,\n      \"data\": Immutable.Map {},\n    },\n  },\n  \"selectionBefore\": Immutable.Record {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 1,\n    \"isBackward\": false,\n    \"hasFocus\": false,\n  },\n  \"selectionAfter\": Immutable.Record {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 1,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 1,\n    \"isBackward\": false,\n    \"hasFocus\": false,\n  },\n}\n`;\n\nexports[`editor selectionstate is updated if new text matches current selection 1`] = `\nImmutable.Record {\n  \"anchorKey\": \"a\",\n  \"anchorOffset\": 1,\n  \"focusKey\": \"a\",\n  \"focusOffset\": 1,\n  \"isBackward\": false,\n  \"hasFocus\": false,\n}\n`;\n\nexports[`editor selectionstate is updated if new text matches current selection and user selected backwards 1`] = `\nImmutable.Record {\n  \"anchorKey\": \"a\",\n  \"anchorOffset\": 1,\n  \"focusKey\": \"a\",\n  \"focusOffset\": 1,\n  \"isBackward\": false,\n  \"hasFocus\": false,\n}\n`;\n"
  },
  {
    "path": "src/component/handlers/edit/__tests__/editOnBeforeInput-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type DraftEditor from 'DraftEditor.react';\n\nconst CompositeDraftDecorator = require('CompositeDraftDecorator');\nconst ContentBlock = require('ContentBlock');\nconst ContentState = require('ContentState');\nconst EditorState = require('EditorState');\nconst SelectionState = require('SelectionState');\n\nconst onBeforeInput = require('editOnBeforeInput');\n\nconst DEFAULT_SELECTION = {\n  anchorKey: 'a',\n  anchorOffset: 0,\n  focusKey: 'a',\n  focusOffset: 0,\n  isBackward: false,\n};\n\nconst rangedSelection = new SelectionState({\n  ...DEFAULT_SELECTION,\n  focusOffset: 1,\n});\n\nconst rangedSelectionBackwards = new SelectionState({\n  ...DEFAULT_SELECTION,\n  anchorOffset: 1,\n  isBackward: true,\n});\n\nconst getEditorState = (text: string = 'Arsenal') => {\n  return EditorState.createWithContent(\n    ContentState.createFromBlockArray([\n      new ContentBlock({\n        key: 'a',\n        text,\n      }),\n    ]),\n  );\n};\n\n/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's\n * LTI update could not be added via codemod */\nconst getDraftEditor = (obj): DraftEditor => (obj: any);\n\nconst getInputEvent = (\n  data:\n    | void\n    | string\n    | $TEMPORARY$string<'A'>\n    | $TEMPORARY$string<'O'>\n    | $TEMPORARY$string<'a'>\n    | $TEMPORARY$string<'b'>\n    | $TEMPORARY$string<'f'>\n    | $TEMPORARY$string<'o'>,\n): SyntheticInputEvent<HTMLElement> =>\n  ({\n    data,\n    preventDefault: jest.fn(),\n  }: any);\n\ntest('editor is not updated if no character data is provided', () => {\n  const editorState = EditorState.acceptSelection(\n    getEditorState(),\n    rangedSelection,\n  );\n\n  const editor = getDraftEditor({\n    _latestEditorState: editorState,\n    props: {},\n    update: jest.fn(),\n  });\n\n  onBeforeInput(editor, getInputEvent());\n\n  expect(editor.update).toHaveBeenCalledTimes(0);\n});\n\ntest('editor is not updated if handled by handleBeforeInput', () => {\n  const editorState = EditorState.acceptSelection(\n    getEditorState(),\n    rangedSelection,\n  );\n\n  const editor = getDraftEditor({\n    _latestEditorState: editorState,\n    props: {\n      handleBeforeInput: () => true,\n    },\n    update: jest.fn(),\n  });\n\n  onBeforeInput(editor, getInputEvent('O'));\n\n  expect(editor.update).toHaveBeenCalledTimes(0);\n});\n\ntest('editor is updated with new text if it does not match current selection', () => {\n  const editorState = EditorState.acceptSelection(\n    getEditorState(),\n    rangedSelection,\n  );\n\n  const update = jest.fn();\n  const editor = getDraftEditor({\n    _latestEditorState: editorState,\n    props: {},\n    update,\n  });\n\n  onBeforeInput(editor, getInputEvent('O'));\n\n  expect(update).toHaveBeenCalledTimes(1);\n\n  const newEditorState = update.mock.calls[0][0];\n  expect(newEditorState.getCurrentContent()).toMatchSnapshot();\n});\n\ntest('editor selectionstate is updated if new text matches current selection', () => {\n  const editorState = EditorState.acceptSelection(\n    getEditorState(),\n    rangedSelection,\n  );\n\n  const update = jest.fn();\n  const editor = getDraftEditor({\n    _latestEditorState: editorState,\n    props: {},\n    update,\n  });\n\n  onBeforeInput(editor, getInputEvent('A'));\n\n  expect(update).toHaveBeenCalledTimes(1);\n\n  const newEditorState = update.mock.calls[0][0];\n  expect(newEditorState.getSelection()).toMatchSnapshot();\n});\n\ntest('editor selectionstate is updated if new text matches current selection and user selected backwards', () => {\n  const editorState = EditorState.acceptSelection(\n    getEditorState(),\n    rangedSelectionBackwards,\n  );\n\n  const update = jest.fn();\n  const editor = getDraftEditor({\n    _latestEditorState: editorState,\n    props: {},\n    update,\n  });\n\n  onBeforeInput(editor, getInputEvent('A'));\n\n  expect(update).toHaveBeenCalledTimes(1);\n\n  const newEditorState = update.mock.calls[0][0];\n  expect(newEditorState.getSelection()).toMatchSnapshot();\n});\n\nconst HASHTAG_REGEX = /#[a-z]+/g;\nfunction hashtagStrategy(\n  contentBlock: BlockNodeRecord,\n  callback: (start: number, end: number) => void,\n  contentState: ContentState,\n) {\n  findWithRegex(HASHTAG_REGEX, contentBlock, callback);\n}\n\nfunction findWithRegex(\n  regex: RegExp,\n  contentBlock: BlockNodeRecord,\n  callback: (start: number, end: number) => void,\n) {\n  const text = contentBlock.getText();\n  let matchArr = regex.exec(text);\n  while (matchArr !== null) {\n    callback(matchArr.index, matchArr.index + matchArr[0].length);\n    matchArr = regex.exec(text);\n  }\n}\n\nfunction testDecoratorFingerprint(\n  text: string,\n  selection: number,\n  charToInsert:\n    | string\n    | $TEMPORARY$string<'a'>\n    | $TEMPORARY$string<'b'>\n    | $TEMPORARY$string<'f'>\n    | $TEMPORARY$string<'o'>,\n  shouldPrevent: boolean,\n) {\n  const editorState = EditorState.acceptSelection(\n    EditorState.set(getEditorState(text), {\n      decorator: new CompositeDraftDecorator([\n        {\n          strategy: hashtagStrategy,\n          component: null,\n        },\n      ]),\n    }),\n    new SelectionState({\n      ...DEFAULT_SELECTION,\n      anchorOffset: selection,\n      focusOffset: selection,\n    }),\n  );\n\n  const editor = getDraftEditor({\n    _latestEditorState: editorState,\n    _latestCommittedEditorState: editorState,\n    props: {},\n    update: jest.fn(),\n  });\n\n  const ev = getInputEvent(charToInsert);\n  onBeforeInput(editor, ev);\n\n  // $FlowFixMe[method-unbinding] added when improving typing for this parameters\n  expect(ev.preventDefault.mock.calls.length).toBe(shouldPrevent ? 1 : 0);\n}\n\ntest('decorator fingerprint logic bails out of native insertion', () => {\n  const oldGetSelection = global.getSelection;\n  try {\n    global.getSelection = () => ({});\n\n    // Make sure we prevent native insertion in the right cases\n    testDecoratorFingerprint('hi #', 4, 'f', true);\n    testDecoratorFingerprint('x #foo', 3, '#', true);\n    testDecoratorFingerprint('#foobar', 4, ' ', true);\n    testDecoratorFingerprint('#foo', 4, 'b', true);\n    testDecoratorFingerprint('#foo bar #baz', 2, 'o', true);\n    testDecoratorFingerprint('#foo bar #baz', 12, 'a', true);\n\n    // but these are OK to let through\n    testDecoratorFingerprint('#foo bar #baz', 7, 'o', false);\n    testDecoratorFingerprint('start #foo bar #baz end', 5, 'a', false);\n    testDecoratorFingerprint('start #foo bar #baz end', 20, 'a', false);\n  } finally {\n    global.getSelection = oldGetSelection;\n  }\n});\n"
  },
  {
    "path": "src/component/handlers/edit/__tests__/editOnBlur-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst ContentBlock = require('ContentBlock');\nconst ContentState = require('ContentState');\nconst EditorState = require('EditorState');\n\nconst onBlur = require('editOnBlur');\n\nconst getEditorState = (text: string = 'Arsenal') => {\n  return EditorState.createWithContent(\n    ContentState.createFromBlockArray([\n      new ContentBlock({\n        key: 'a',\n        text,\n      }),\n    ]),\n  );\n};\n\nconst getBlurEvent = (currentTarget: HTMLDivElement) => ({\n  currentTarget,\n});\n\nfunction withGlobalGetSelectionAs(\n  getSelectionValue:\n    | $TEMPORARY$object<{...}>\n    | $TEMPORARY$object<{\n        anchorNode: Text,\n        focusNode: Text,\n        rangeCount: number,\n        removeAllRanges: JestMockFn<$ReadOnlyArray<mixed>, mixed>,\n      }> = {},\n  callback: () => void,\n) {\n  const oldGetSelection = global.getSelection;\n  try {\n    global.getSelection = () => {\n      return getSelectionValue;\n    };\n    callback();\n  } finally {\n    global.getSelection = oldGetSelection;\n  }\n}\n\ntest('editor removes selection on blur (default behaviour)', () => {\n  const anchorNodeText = 'react draftjs';\n  const anchorNode = document.createTextNode(anchorNodeText);\n  const globalSelection = {\n    anchorNode,\n    focusNode: anchorNode,\n    removeAllRanges: jest.fn(),\n    rangeCount: 1,\n  };\n\n  const editorNode = document.createElement('div');\n  editorNode.appendChild(anchorNode);\n\n  withGlobalGetSelectionAs(globalSelection, () => {\n    const editorState = getEditorState(anchorNodeText);\n    const editor = {\n      _latestEditorState: editorState,\n      props: {\n        preserveSelectionOnBlur: false,\n      },\n      editor: editorNode,\n    };\n\n    // $FlowExpectedError[incompatible-call]\n    onBlur(editor, getBlurEvent(editorNode));\n\n    expect(globalSelection.removeAllRanges).toHaveBeenCalledTimes(1);\n  });\n});\n\ntest('editor preserves selection on blur', () => {\n  const anchorNodeText = 'react draftjs';\n  const anchorNode = document.createTextNode(anchorNodeText);\n  const globalSelection = {\n    anchorNode,\n    focusNode: anchorNode,\n    removeAllRanges: jest.fn(),\n    rangeCount: 1,\n  };\n\n  const editorNode = document.createElement('div');\n  editorNode.appendChild(anchorNode);\n\n  withGlobalGetSelectionAs(globalSelection, () => {\n    const editorState = getEditorState(anchorNodeText);\n    const editor = {\n      _latestEditorState: editorState,\n      props: {\n        preserveSelectionOnBlur: true,\n      },\n      editor: editorNode,\n    };\n\n    // $FlowExpectedError[incompatible-call]\n    onBlur(editor, getBlurEvent(editorNode));\n\n    expect(globalSelection.removeAllRanges).toHaveBeenCalledTimes(0);\n  });\n});\n"
  },
  {
    "path": "src/component/handlers/edit/__tests__/editOnInput-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst ContentBlock = require('ContentBlock');\nconst ContentState = require('ContentState');\nconst EditorState = require('EditorState');\n\nconst onInput = require('editOnInput');\n\njest.mock('findAncestorOffsetKey', () => jest.fn(() => 'blockkey-0-0'));\njest.mock('keyCommandPlainBackspace', () => jest.fn(() => ({})));\n\nconst getEditorState = (text: string = '') => {\n  return EditorState.createWithContent(\n    ContentState.createFromBlockArray([\n      new ContentBlock({\n        key: 'blockkey',\n        text,\n      }),\n    ]),\n  );\n};\n\nfunction withGlobalGetSelectionAs(\n  getSelectionValue:\n    | $TEMPORARY$object<{...}>\n    | $TEMPORARY$object<{anchorNode: Text}> = {},\n  callback: () => void,\n) {\n  const oldGetSelection = global.getSelection;\n  try {\n    global.getSelection = () => getSelectionValue;\n    callback();\n  } finally {\n    global.getSelection = oldGetSelection;\n  }\n}\n\ntest('restoreEditorDOM and keyCommandPlainBackspace are NOT called when the `inputType` is not from a backspace press', () => {\n  const anchorNodeText = 'react draftjs';\n  const globalSelection = {\n    anchorNode: document.createTextNode(anchorNodeText),\n  };\n  withGlobalGetSelectionAs(globalSelection, () => {\n    const editorState = getEditorState(anchorNodeText);\n    const editorNode = document.createElement('div');\n    const editor = {\n      _latestEditorState: editorState,\n      props: {},\n      update: jest.fn(),\n      restoreEditorDOM: jest.fn(),\n      editor: editorNode,\n    };\n\n    const inputEvent = {\n      nativeEvent: {inputType: 'insetText'},\n      currentTarget: editorNode,\n    };\n\n    // $FlowExpectedError[incompatible-call]\n    onInput(editor, inputEvent);\n\n    expect(require('keyCommandPlainBackspace')).toHaveBeenCalledTimes(0);\n    expect(editor.restoreEditorDOM).toHaveBeenCalledTimes(0);\n    expect(editor.update).toHaveBeenCalledTimes(0);\n  });\n});\n\ntest('restoreEditorDOM and keyCommandPlainBackspace are called when backspace is pressed', () => {\n  const anchorNodeText = 'react draftjs';\n  const globalSelection = {\n    anchorNode: document.createTextNode(anchorNodeText),\n  };\n  withGlobalGetSelectionAs(globalSelection, () => {\n    const editorState = getEditorState(anchorNodeText);\n    const editorNode = document.createElement('div');\n    const editor = {\n      _latestEditorState: editorState,\n      props: {},\n      update: jest.fn(),\n      restoreEditorDOM: jest.fn(),\n      editor: editorNode,\n    };\n\n    const inputEvent = {\n      // When Backspace is pressed and input-type is supported, an event with\n      // inputType === 'deleteContentBackward' is triggered by the browser.\n      nativeEvent: {inputType: 'deleteContentBackward'},\n      currentTarget: editorNode,\n    };\n\n    // $FlowExpectedError[incompatible-call]\n    onInput(editor, inputEvent);\n\n    // $FlowExpectedError[prop-missing]\n    const newEditorState = require('keyCommandPlainBackspace').mock.results[0]\n      .value;\n    expect(require('keyCommandPlainBackspace')).toHaveBeenCalledWith(\n      editorState,\n    );\n    expect(editor.restoreEditorDOM).toHaveBeenCalledTimes(1);\n    expect(editor.update).toHaveBeenCalledWith(newEditorState);\n  });\n});\n"
  },
  {
    "path": "src/component/handlers/edit/commands/SecondaryClipboard.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockMap} from 'BlockMap';\nimport type SelectionState from 'SelectionState';\n\nconst DraftModifier = require('DraftModifier');\nconst EditorState = require('EditorState');\n\nconst getContentStateFragment = require('getContentStateFragment');\nconst nullthrows = require('nullthrows');\n\nlet clipboard: ?BlockMap = null;\n\n/**\n * Some systems offer a \"secondary\" clipboard to allow quick internal cut\n * and paste behavior. For instance, Ctrl+K (cut) and Ctrl+Y (paste).\n */\nconst SecondaryClipboard = {\n  cut(editorState: EditorState): EditorState {\n    const content = editorState.getCurrentContent();\n    const selection = editorState.getSelection();\n    let targetRange: ?SelectionState = null;\n\n    if (selection.isCollapsed()) {\n      const anchorKey = selection.getAnchorKey();\n      const blockEnd = content.getBlockForKey(anchorKey).getLength();\n\n      if (blockEnd === selection.getAnchorOffset()) {\n        const keyAfter = content.getKeyAfter(anchorKey);\n        if (keyAfter == null) {\n          return editorState;\n        }\n        targetRange = selection.set('focusKey', keyAfter).set('focusOffset', 0);\n      } else {\n        targetRange = selection.set('focusOffset', blockEnd);\n      }\n    } else {\n      targetRange = selection;\n    }\n\n    targetRange = nullthrows(targetRange);\n    // TODO: This should actually append to the current state when doing\n    // successive ^K commands without any other cursor movement\n    clipboard = getContentStateFragment(content, targetRange);\n\n    const afterRemoval = DraftModifier.removeRange(\n      content,\n      targetRange,\n      'forward',\n    );\n\n    if (afterRemoval === content) {\n      return editorState;\n    }\n\n    return EditorState.push(editorState, afterRemoval, 'remove-range');\n  },\n\n  paste(editorState: EditorState): EditorState {\n    if (!clipboard) {\n      return editorState;\n    }\n\n    const newContent = DraftModifier.replaceWithFragment(\n      editorState.getCurrentContent(),\n      editorState.getSelection(),\n      // $FlowFixMe[incompatible-call]\n      clipboard,\n    );\n\n    return EditorState.push(editorState, newContent, 'insert-fragment');\n  },\n};\n\nmodule.exports = SecondaryClipboard;\n"
  },
  {
    "path": "src/component/handlers/edit/commands/__tests__/SecondaryClipboard-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\njest.mock('generateRandomKey');\n\nconst toggleExperimentalTreeDataSupport = (enabled: boolean) => {\n  jest.doMock('gkx', () => name => {\n    return name === 'draft_tree_data_support' ? enabled : false;\n  });\n};\n\n// Seems to be important to put this at the top\ntoggleExperimentalTreeDataSupport(true);\n\nconst BlockMapBuilder = require('BlockMapBuilder');\nconst ContentBlockNode = require('ContentBlockNode');\nconst EditorState = require('EditorState');\nconst SecondaryClipboard = require('SecondaryClipboard');\nconst SelectionState = require('SelectionState');\n\nconst getSampleStateForTesting = require('getSampleStateForTesting');\nconst Immutable = require('immutable');\n\nconst {List} = Immutable;\n\nconst {contentState} = getSampleStateForTesting();\n\nconst contentBlockNodes = [\n  new ContentBlockNode({\n    key: 'A',\n    nextSibling: 'B',\n    text: 'Alpha',\n    type: 'blockquote',\n  }),\n  new ContentBlockNode({\n    key: 'B',\n    prevSibling: 'A',\n    nextSibling: 'G',\n    type: 'ordered-list-item',\n    children: List(['C', 'F']),\n  }),\n  new ContentBlockNode({\n    parent: 'B',\n    key: 'C',\n    nextSibling: 'F',\n    type: 'blockquote',\n    children: List(['D', 'E']),\n  }),\n  new ContentBlockNode({\n    parent: 'C',\n    key: 'D',\n    nextSibling: 'E',\n    type: 'header-two',\n    text: 'Delta',\n  }),\n  new ContentBlockNode({\n    parent: 'C',\n    key: 'E',\n    prevSibling: 'D',\n    type: 'unstyled',\n    text: 'Elephant',\n  }),\n  new ContentBlockNode({\n    parent: 'B',\n    key: 'F',\n    prevSibling: 'C',\n    type: 'code-block',\n    text: 'Fire',\n  }),\n  new ContentBlockNode({\n    key: 'G',\n    prevSibling: 'B',\n    nextSibling: 'H',\n    type: 'ordered-list-item',\n    text: 'Gorila',\n  }),\n  new ContentBlockNode({\n    key: 'H',\n    prevSibling: 'G',\n    nextSibling: 'I',\n    text: ' ',\n    type: 'atomic',\n  }),\n  new ContentBlockNode({\n    key: 'I',\n    prevSibling: 'H',\n    text: 'last',\n    type: 'unstyled',\n  }),\n];\n\nconst assertCutOperation = (\n  operation: (editorState: EditorState) => EditorState,\n  selection:\n    | $TEMPORARY$object<{...}>\n    | $TEMPORARY$object<{\n        anchorKey: $TEMPORARY$string<'E'>,\n        anchorOffset: number,\n        focusKey: $TEMPORARY$string<'E'>,\n        focusOffset: number,\n      }>\n    | $TEMPORARY$object<{\n        anchorKey: $TEMPORARY$string<'H'>,\n        anchorOffset: number,\n        focusKey: $TEMPORARY$string<'H'>,\n        focusOffset: number,\n      }>\n    | $TEMPORARY$object<{\n        anchorKey: $TEMPORARY$string<'I'>,\n        anchorOffset: number,\n        focusKey: $TEMPORARY$string<'I'>,\n        focusOffset: number,\n      }> = {},\n  content: $TEMPORARY$array<ContentBlockNode> = contentBlockNodes,\n) => {\n  const result = operation(\n    EditorState.forceSelection(\n      EditorState.createWithContent(\n        contentState.setBlockMap(BlockMapBuilder.createFromArray(content)),\n      ),\n      SelectionState.createEmpty(content[0].key).merge(selection),\n    ),\n  );\n  const expected = result.getCurrentContent().getBlockMap().toJS();\n\n  expect(expected).toMatchSnapshot();\n};\n\ntest(`in the middle of a block, cut removes the remainder of the block`, () => {\n  assertCutOperation(editorState => SecondaryClipboard.cut(editorState), {\n    anchorKey: 'E',\n    anchorOffset: contentBlockNodes[4].getLength() - 2,\n    focusKey: 'E',\n    focusOffset: contentBlockNodes[4].getLength() - 2,\n  });\n});\n\ntest(`at the end of an intermediate block, cut merges with the adjacent content block`, () => {\n  assertCutOperation(editorState => SecondaryClipboard.cut(editorState), {\n    anchorKey: 'H',\n    anchorOffset: contentBlockNodes[7].getLength(),\n    focusKey: 'H',\n    focusOffset: contentBlockNodes[7].getLength(),\n  });\n});\n\ntest(`at the end of the last block, cut is a no-op`, () => {\n  assertCutOperation(editorState => SecondaryClipboard.cut(editorState), {\n    anchorKey: 'I',\n    anchorOffset: contentBlockNodes[8].getLength(),\n    focusKey: 'I',\n    focusOffset: contentBlockNodes[8].getLength(),\n  });\n});\n"
  },
  {
    "path": "src/component/handlers/edit/commands/__tests__/__snapshots__/SecondaryClipboard-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`at the end of an intermediate block, cut merges with the adjacent content block 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"blockquote\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"blockquote\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"header-two\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Elephant\",\n    \"type\": \"unstyled\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"code-block\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"H\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \" last\",\n    \"type\": \"atomic\",\n  },\n}\n`;\n\nexports[`at the end of the last block, cut is a no-op 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"blockquote\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"blockquote\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"header-two\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Elephant\",\n    \"type\": \"unstyled\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"code-block\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"H\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": \"I\",\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"H\",\n    \"text\": \"last\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`in the middle of a block, cut removes the remainder of the block 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"blockquote\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"blockquote\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"header-two\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Elepha\",\n    \"type\": \"unstyled\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"code-block\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"H\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": \"I\",\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"H\",\n    \"text\": \"last\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n"
  },
  {
    "path": "src/component/handlers/edit/commands/__tests__/__snapshots__/removeTextWithStrategy-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`across blocks with forward delete is a no-op 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"blockquote\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"blockquote\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"header-two\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"code-block\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"H\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": \"I\",\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"H\",\n    \"text\": \"last\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`at end of a leaf block and sibling is another leaf block forward delete concatenates 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"blockquote\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"blockquote\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"DeltaElephant\",\n    \"type\": \"header-two\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"code-block\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"H\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": \"I\",\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"H\",\n    \"text\": \"last\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`at end of a leaf block and sibling is not another leaf block forward delete is no-op 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"blockquote\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"blockquote\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"header-two\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"ElephantFire\",\n    \"type\": \"unstyled\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"H\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": \"I\",\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"H\",\n    \"text\": \"last\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`at end of a leaf block and sibling is not another leaf block forward delete is no-op 2`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"blockquote\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"blockquote\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"header-two\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"ElephantFire\",\n    \"type\": \"unstyled\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"H\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": \"I\",\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"H\",\n    \"text\": \"last\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n"
  },
  {
    "path": "src/component/handlers/edit/commands/__tests__/removeTextWithStrategy-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\nimport type ContentState from 'ContentState';\n\nconst BlockMapBuilder = require('BlockMapBuilder');\nconst ContentBlockNode = require('ContentBlockNode');\nconst EditorState = require('EditorState');\nconst SelectionState = require('SelectionState');\nconst UnicodeUtils = require('UnicodeUtils');\n\nconst getSampleStateForTesting = require('getSampleStateForTesting');\nconst Immutable = require('immutable');\nconst moveSelectionForward = require('moveSelectionForward');\nconst removeTextWithStrategy = require('removeTextWithStrategy');\n\njest.mock('generateRandomKey');\nconst toggleExperimentalTreeDataSupport = (enabled: boolean) => {\n  jest.doMock('gkx', () => name => {\n    return name === 'draft_tree_data_support' ? enabled : false;\n  });\n};\n// Seems to be important to put this at the top\ntoggleExperimentalTreeDataSupport(true);\n\nconst {List} = Immutable;\n\nconst {contentState} = getSampleStateForTesting();\n\nconst contentBlockNodes = [\n  new ContentBlockNode({\n    key: 'A',\n    nextSibling: 'B',\n    text: 'Alpha',\n    type: 'blockquote',\n  }),\n  new ContentBlockNode({\n    key: 'B',\n    prevSibling: 'A',\n    nextSibling: 'G',\n    type: 'ordered-list-item',\n    children: List(['C', 'F']),\n  }),\n  new ContentBlockNode({\n    parent: 'B',\n    key: 'C',\n    nextSibling: 'F',\n    type: 'blockquote',\n    children: List(['D', 'E']),\n  }),\n  new ContentBlockNode({\n    parent: 'C',\n    key: 'D',\n    nextSibling: 'E',\n    type: 'header-two',\n    text: 'Delta',\n  }),\n  new ContentBlockNode({\n    parent: 'C',\n    key: 'E',\n    prevSibling: 'D',\n    type: 'unstyled',\n    text: 'Elephant',\n  }),\n  new ContentBlockNode({\n    parent: 'B',\n    key: 'F',\n    prevSibling: 'C',\n    type: 'code-block',\n    text: 'Fire',\n  }),\n  new ContentBlockNode({\n    key: 'G',\n    prevSibling: 'B',\n    nextSibling: 'H',\n    type: 'ordered-list-item',\n    text: 'Gorila',\n  }),\n  new ContentBlockNode({\n    key: 'H',\n    prevSibling: 'G',\n    nextSibling: 'I',\n    text: ' ',\n    type: 'atomic',\n  }),\n  new ContentBlockNode({\n    key: 'I',\n    prevSibling: 'H',\n    text: 'last',\n    type: 'unstyled',\n  }),\n];\n\nconst assertRemoveTextOperation = (\n  operation: (editorState: EditorState) => ContentState,\n  selection:\n    | $TEMPORARY$object<{...}>\n    | $TEMPORARY$object<{\n        anchorKey: $TEMPORARY$string<'D'>,\n        anchorOffset: number,\n        focusKey: $TEMPORARY$string<'D'>,\n        focusOffset: number,\n      }>\n    | $TEMPORARY$object<{\n        anchorKey: $TEMPORARY$string<'D'>,\n        anchorOffset: number,\n        focusKey: $TEMPORARY$string<'E'>,\n        focusOffset: number,\n      }>\n    | $TEMPORARY$object<{\n        anchorKey: $TEMPORARY$string<'E'>,\n        anchorOffset: number,\n        focusKey: $TEMPORARY$string<'E'>,\n        focusOffset: number,\n      }> = {},\n  content: $TEMPORARY$array<ContentBlockNode> = contentBlockNodes,\n) => {\n  const result = operation(\n    EditorState.forceSelection(\n      EditorState.createWithContent(\n        contentState.setBlockMap(BlockMapBuilder.createFromArray(content)),\n      ),\n      SelectionState.createEmpty(content[0].key).merge(selection),\n    ),\n  );\n  const expected = result.getBlockMap().toJS();\n\n  expect(expected).toMatchSnapshot();\n};\n\ntest(`at end of a leaf block and sibling is another leaf block forward delete concatenates`, () => {\n  assertRemoveTextOperation(\n    editorState =>\n      removeTextWithStrategy(\n        editorState,\n        strategyState => {\n          const selection = strategyState.getSelection();\n          const content = strategyState.getCurrentContent();\n          const key = selection.getAnchorKey();\n          const offset = selection.getAnchorOffset();\n          const charAhead = content.getBlockForKey(key).getText()[offset];\n          return moveSelectionForward(\n            strategyState,\n            charAhead ? UnicodeUtils.getUTF16Length(charAhead, 0) : 1,\n          );\n        },\n        'forward',\n      ),\n    {\n      anchorKey: 'D',\n      anchorOffset: contentBlockNodes[3].getLength(),\n      focusKey: 'D',\n      focusOffset: contentBlockNodes[3].getLength(),\n    },\n  );\n});\n\ntest(`at end of a leaf block and sibling is not another leaf block forward delete is no-op`, () => {\n  // no next sibling\n  assertRemoveTextOperation(\n    editorState =>\n      removeTextWithStrategy(\n        editorState,\n        strategyState => {\n          const selection = strategyState.getSelection();\n          const content = strategyState.getCurrentContent();\n          const key = selection.getAnchorKey();\n          const offset = selection.getAnchorOffset();\n          const charAhead = content.getBlockForKey(key).getText()[offset];\n          return moveSelectionForward(\n            strategyState,\n            charAhead ? UnicodeUtils.getUTF16Length(charAhead, 0) : 1,\n          );\n        },\n        'forward',\n      ),\n    {\n      anchorKey: 'E',\n      anchorOffset: contentBlockNodes[4].getLength(),\n      focusKey: 'E',\n      focusOffset: contentBlockNodes[4].getLength(),\n    },\n  );\n  // next sibling is not a leaf\n  assertRemoveTextOperation(\n    editorState =>\n      removeTextWithStrategy(\n        editorState,\n        strategyState => {\n          const selection = strategyState.getSelection();\n          const content = strategyState.getCurrentContent();\n          const key = selection.getAnchorKey();\n          const offset = selection.getAnchorOffset();\n          const charAhead = content.getBlockForKey(key).getText()[offset];\n          return moveSelectionForward(\n            strategyState,\n            charAhead ? UnicodeUtils.getUTF16Length(charAhead, 0) : 1,\n          );\n        },\n        'forward',\n      ),\n    {\n      anchorKey: 'E',\n      anchorOffset: contentBlockNodes[4].getLength(),\n      focusKey: 'E',\n      focusOffset: contentBlockNodes[4].getLength(),\n    },\n  );\n});\n\ntest(`across blocks with forward delete is a no-op`, () => {\n  assertRemoveTextOperation(\n    editorState =>\n      removeTextWithStrategy(\n        editorState,\n        strategyState => {\n          const selection = strategyState.getSelection();\n          const content = strategyState.getCurrentContent();\n          const key = selection.getAnchorKey();\n          const offset = selection.getAnchorOffset();\n          const charAhead = content.getBlockForKey(key).getText()[offset];\n          return moveSelectionForward(\n            strategyState,\n            charAhead ? UnicodeUtils.getUTF16Length(charAhead, 0) : 1,\n          );\n        },\n        'forward',\n      ),\n    {\n      anchorKey: 'D',\n      anchorOffset: contentBlockNodes[3].getLength(),\n      focusKey: 'E',\n      focusOffset: contentBlockNodes[4].getLength(),\n    },\n  );\n});\n"
  },
  {
    "path": "src/component/handlers/edit/commands/keyCommandBackspaceToStartOfLine.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {SelectionObject} from 'DraftDOMTypes';\n\nconst EditorState = require('EditorState');\n\nconst expandRangeToStartOfLine = require('expandRangeToStartOfLine');\nconst getDraftEditorSelectionWithNodes = require('getDraftEditorSelectionWithNodes');\nconst moveSelectionBackward = require('moveSelectionBackward');\nconst removeTextWithStrategy = require('removeTextWithStrategy');\n\nfunction keyCommandBackspaceToStartOfLine(\n  editorState: EditorState,\n  e: SyntheticKeyboardEvent<HTMLElement>,\n): EditorState {\n  const afterRemoval = removeTextWithStrategy(\n    editorState,\n    strategyState => {\n      const selection = strategyState.getSelection();\n      if (selection.isCollapsed() && selection.getAnchorOffset() === 0) {\n        return moveSelectionBackward(strategyState, 1);\n      }\n      const {ownerDocument} = e.currentTarget;\n      const domSelection: SelectionObject =\n        ownerDocument.defaultView.getSelection();\n      // getRangeAt can technically throw if there's no selection, but we know\n      // there is one here because text editor has focus (the cursor is a\n      // selection of length 0). Therefore, we don't need to wrap this in a\n      // try-catch block.\n      let range = domSelection.getRangeAt(0);\n      range = expandRangeToStartOfLine(range);\n\n      return getDraftEditorSelectionWithNodes(\n        strategyState,\n        null,\n        range.endContainer,\n        range.endOffset,\n        range.startContainer,\n        range.startOffset,\n      ).selectionState;\n    },\n    'backward',\n  );\n\n  if (afterRemoval === editorState.getCurrentContent()) {\n    return editorState;\n  }\n\n  return EditorState.push(editorState, afterRemoval, 'remove-range');\n}\n\nmodule.exports = keyCommandBackspaceToStartOfLine;\n"
  },
  {
    "path": "src/component/handlers/edit/commands/keyCommandBackspaceWord.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst DraftRemovableWord = require('DraftRemovableWord');\nconst EditorState = require('EditorState');\n\nconst moveSelectionBackward = require('moveSelectionBackward');\nconst removeTextWithStrategy = require('removeTextWithStrategy');\n\n/**\n * Delete the word that is left of the cursor, as well as any spaces or\n * punctuation after the word.\n */\nfunction keyCommandBackspaceWord(editorState: EditorState): EditorState {\n  const afterRemoval = removeTextWithStrategy(\n    editorState,\n    strategyState => {\n      const selection = strategyState.getSelection();\n      const offset = selection.getStartOffset();\n      // If there are no words before the cursor, remove the preceding newline.\n      if (offset === 0) {\n        return moveSelectionBackward(strategyState, 1);\n      }\n      const key = selection.getStartKey();\n      const content = strategyState.getCurrentContent();\n      const text = content.getBlockForKey(key).getText().slice(0, offset);\n      const toRemove = DraftRemovableWord.getBackward(text);\n      return moveSelectionBackward(strategyState, toRemove.length || 1);\n    },\n    'backward',\n  );\n\n  if (afterRemoval === editorState.getCurrentContent()) {\n    return editorState;\n  }\n\n  return EditorState.push(editorState, afterRemoval, 'remove-range');\n}\n\nmodule.exports = keyCommandBackspaceWord;\n"
  },
  {
    "path": "src/component/handlers/edit/commands/keyCommandDeleteWord.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst DraftRemovableWord = require('DraftRemovableWord');\nconst EditorState = require('EditorState');\n\nconst moveSelectionForward = require('moveSelectionForward');\nconst removeTextWithStrategy = require('removeTextWithStrategy');\n\n/**\n * Delete the word that is right of the cursor, as well as any spaces or\n * punctuation before the word.\n */\nfunction keyCommandDeleteWord(editorState: EditorState): EditorState {\n  const afterRemoval = removeTextWithStrategy(\n    editorState,\n    strategyState => {\n      const selection = strategyState.getSelection();\n      const offset = selection.getStartOffset();\n      const key = selection.getStartKey();\n      const content = strategyState.getCurrentContent();\n      const text = content.getBlockForKey(key).getText().slice(offset);\n      const toRemove = DraftRemovableWord.getForward(text);\n\n      // If there are no words in front of the cursor, remove the newline.\n      return moveSelectionForward(strategyState, toRemove.length || 1);\n    },\n    'forward',\n  );\n\n  if (afterRemoval === editorState.getCurrentContent()) {\n    return editorState;\n  }\n\n  return EditorState.push(editorState, afterRemoval, 'remove-range');\n}\n\nmodule.exports = keyCommandDeleteWord;\n"
  },
  {
    "path": "src/component/handlers/edit/commands/keyCommandInsertNewline.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst DraftModifier = require('DraftModifier');\nconst EditorState = require('EditorState');\n\nfunction keyCommandInsertNewline(editorState: EditorState): EditorState {\n  const contentState = DraftModifier.splitBlock(\n    editorState.getCurrentContent(),\n    editorState.getSelection(),\n  );\n  return EditorState.push(editorState, contentState, 'split-block');\n}\n\nmodule.exports = keyCommandInsertNewline;\n"
  },
  {
    "path": "src/component/handlers/edit/commands/keyCommandMoveSelectionToEndOfBlock.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst EditorState = require('EditorState');\n\n/**\n * See comment for `moveSelectionToStartOfBlock`.\n */\nfunction keyCommandMoveSelectionToEndOfBlock(\n  editorState: EditorState,\n): EditorState {\n  const selection = editorState.getSelection();\n  const endKey = selection.getEndKey();\n  const content = editorState.getCurrentContent();\n  const textLength = content.getBlockForKey(endKey).getLength();\n  return EditorState.set(editorState, {\n    selection: selection.merge({\n      anchorKey: endKey,\n      anchorOffset: textLength,\n      focusKey: endKey,\n      focusOffset: textLength,\n      isBackward: false,\n    }),\n    forceSelection: true,\n  });\n}\n\nmodule.exports = keyCommandMoveSelectionToEndOfBlock;\n"
  },
  {
    "path": "src/component/handlers/edit/commands/keyCommandMoveSelectionToStartOfBlock.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst EditorState = require('EditorState');\n\n/**\n * Collapse selection at the start of the first selected block. This is used\n * for Firefox versions that attempt to navigate forward/backward instead of\n * moving the cursor. Other browsers are able to move the cursor natively.\n */\nfunction keyCommandMoveSelectionToStartOfBlock(\n  editorState: EditorState,\n): EditorState {\n  const selection = editorState.getSelection();\n  const startKey = selection.getStartKey();\n  return EditorState.set(editorState, {\n    selection: selection.merge({\n      anchorKey: startKey,\n      anchorOffset: 0,\n      focusKey: startKey,\n      focusOffset: 0,\n      isBackward: false,\n    }),\n    forceSelection: true,\n  });\n}\n\nmodule.exports = keyCommandMoveSelectionToStartOfBlock;\n"
  },
  {
    "path": "src/component/handlers/edit/commands/keyCommandPlainBackspace.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst EditorState = require('EditorState');\nconst UnicodeUtils = require('UnicodeUtils');\n\nconst moveSelectionBackward = require('moveSelectionBackward');\nconst removeTextWithStrategy = require('removeTextWithStrategy');\n\n/**\n * Remove the selected range. If the cursor is collapsed, remove the preceding\n * character. This operation is Unicode-aware, so removing a single character\n * will remove a surrogate pair properly as well.\n */\nfunction keyCommandPlainBackspace(editorState: EditorState): EditorState {\n  const afterRemoval = removeTextWithStrategy(\n    editorState,\n    strategyState => {\n      const selection = strategyState.getSelection();\n      const content = strategyState.getCurrentContent();\n      const key = selection.getAnchorKey();\n      const offset = selection.getAnchorOffset();\n      const charBehind = content.getBlockForKey(key).getText()[offset - 1];\n      return moveSelectionBackward(\n        strategyState,\n        charBehind ? UnicodeUtils.getUTF16Length(charBehind, 0) : 1,\n      );\n    },\n    'backward',\n  );\n\n  if (afterRemoval === editorState.getCurrentContent()) {\n    return editorState;\n  }\n\n  const selection = editorState.getSelection();\n  return EditorState.push(\n    editorState,\n    afterRemoval.setSelectionBefore(selection),\n    selection.isCollapsed() ? 'backspace-character' : 'remove-range',\n  );\n}\n\nmodule.exports = keyCommandPlainBackspace;\n"
  },
  {
    "path": "src/component/handlers/edit/commands/keyCommandPlainDelete.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst EditorState = require('EditorState');\nconst UnicodeUtils = require('UnicodeUtils');\n\nconst moveSelectionForward = require('moveSelectionForward');\nconst removeTextWithStrategy = require('removeTextWithStrategy');\n\n/**\n * Remove the selected range. If the cursor is collapsed, remove the following\n * character. This operation is Unicode-aware, so removing a single character\n * will remove a surrogate pair properly as well.\n */\nfunction keyCommandPlainDelete(editorState: EditorState): EditorState {\n  const afterRemoval = removeTextWithStrategy(\n    editorState,\n    strategyState => {\n      const selection = strategyState.getSelection();\n      const content = strategyState.getCurrentContent();\n      const key = selection.getAnchorKey();\n      const offset = selection.getAnchorOffset();\n      const charAhead = content.getBlockForKey(key).getText()[offset];\n      return moveSelectionForward(\n        strategyState,\n        charAhead ? UnicodeUtils.getUTF16Length(charAhead, 0) : 1,\n      );\n    },\n    'forward',\n  );\n\n  if (afterRemoval === editorState.getCurrentContent()) {\n    return editorState;\n  }\n\n  const selection = editorState.getSelection();\n\n  return EditorState.push(\n    editorState,\n    afterRemoval.setSelectionBefore(selection),\n    selection.isCollapsed() ? 'delete-character' : 'remove-range',\n  );\n}\n\nmodule.exports = keyCommandPlainDelete;\n"
  },
  {
    "path": "src/component/handlers/edit/commands/keyCommandTransposeCharacters.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst DraftModifier = require('DraftModifier');\nconst EditorState = require('EditorState');\n\nconst getContentStateFragment = require('getContentStateFragment');\n\n/**\n * Transpose the characters on either side of a collapsed cursor, or\n * if the cursor is at the end of the block, transpose the last two\n * characters.\n */\nfunction keyCommandTransposeCharacters(editorState: EditorState): EditorState {\n  const selection = editorState.getSelection();\n  if (!selection.isCollapsed()) {\n    return editorState;\n  }\n\n  const offset = selection.getAnchorOffset();\n  if (offset === 0) {\n    return editorState;\n  }\n\n  const blockKey = selection.getAnchorKey();\n  const content = editorState.getCurrentContent();\n  const block = content.getBlockForKey(blockKey);\n  const length = block.getLength();\n\n  // Nothing to transpose if there aren't two characters.\n  if (length <= 1) {\n    return editorState;\n  }\n\n  let removalRange;\n  let finalSelection;\n\n  if (offset === length) {\n    // The cursor is at the end of the block. Swap the last two characters.\n    removalRange = selection.set('anchorOffset', offset - 1);\n    finalSelection = selection;\n  } else {\n    removalRange = selection.set('focusOffset', offset + 1);\n    finalSelection = removalRange.set('anchorOffset', offset + 1);\n  }\n\n  // Extract the character to move as a fragment. This preserves its\n  // styling and entity, if any.\n  const movedFragment = getContentStateFragment(content, removalRange);\n  const afterRemoval = DraftModifier.removeRange(\n    content,\n    removalRange,\n    'backward',\n  );\n\n  // After the removal, the insertion target is one character back.\n  const selectionAfter = afterRemoval.getSelectionAfter();\n  const targetOffset = selectionAfter.getAnchorOffset() - 1;\n  const targetRange = selectionAfter.merge({\n    anchorOffset: targetOffset,\n    focusOffset: targetOffset,\n  });\n\n  const afterInsert = DraftModifier.replaceWithFragment(\n    afterRemoval,\n    targetRange,\n    movedFragment,\n  );\n\n  const newEditorState = EditorState.push(\n    editorState,\n    afterInsert,\n    'insert-fragment',\n  );\n\n  return EditorState.acceptSelection(newEditorState, finalSelection);\n}\n\nmodule.exports = keyCommandTransposeCharacters;\n"
  },
  {
    "path": "src/component/handlers/edit/commands/keyCommandUndo.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst EditorState = require('EditorState');\n\nfunction keyCommandUndo(\n  e: SyntheticKeyboardEvent<>,\n  editorState: EditorState,\n  updateFn: (editorState: EditorState) => void,\n): void {\n  const undoneState = EditorState.undo(editorState);\n\n  // If the last change to occur was a spellcheck change, allow the undo\n  // event to fall through to the browser. This allows the browser to record\n  // the unwanted change, which should soon lead it to learn not to suggest\n  // the correction again.\n  if (editorState.getLastChangeType() === 'spellcheck-change') {\n    const nativelyRenderedContent = undoneState.getCurrentContent();\n    updateFn(EditorState.set(undoneState, {nativelyRenderedContent}));\n    return;\n  }\n\n  // Otheriwse, manage the undo behavior manually.\n  e.preventDefault();\n  if (!editorState.getNativelyRenderedContent()) {\n    updateFn(undoneState);\n    return;\n  }\n\n  // Trigger a re-render with the current content state to ensure that the\n  // component tree has up-to-date props for comparison.\n  updateFn(EditorState.set(editorState, {nativelyRenderedContent: null}));\n\n  // Wait to ensure that the re-render has occurred before performing\n  // the undo action.\n  setTimeout(() => {\n    updateFn(undoneState);\n  }, 0);\n}\n\nmodule.exports = keyCommandUndo;\n"
  },
  {
    "path": "src/component/handlers/edit/commands/moveSelectionBackward.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type EditorState from 'EditorState';\nimport type SelectionState from 'SelectionState';\n\nconst warning = require('warning');\n\n/**\n * Given a collapsed selection, move the focus `maxDistance` backward within\n * the selected block. If the selection will go beyond the start of the block,\n * move focus to the end of the previous block, but no further.\n *\n * This function is not Unicode-aware, so surrogate pairs will be treated\n * as having length 2.\n */\nfunction moveSelectionBackward(\n  editorState: EditorState,\n  maxDistance: number,\n): SelectionState {\n  const selection = editorState.getSelection();\n  // Should eventually make this an invariant\n  warning(\n    selection.isCollapsed(),\n    'moveSelectionBackward should only be called with a collapsed SelectionState',\n  );\n  const content = editorState.getCurrentContent();\n  const key = selection.getStartKey();\n  const offset = selection.getStartOffset();\n\n  let focusKey = key;\n  let focusOffset = 0;\n\n  if (maxDistance > offset) {\n    const keyBefore = content.getKeyBefore(key);\n    if (keyBefore == null) {\n      focusKey = key;\n    } else {\n      focusKey = keyBefore;\n      const blockBefore = content.getBlockForKey(keyBefore);\n      focusOffset = blockBefore.getText().length;\n    }\n  } else {\n    focusOffset = offset - maxDistance;\n  }\n\n  return selection.merge({\n    focusKey,\n    focusOffset,\n    isBackward: true,\n  });\n}\n\nmodule.exports = moveSelectionBackward;\n"
  },
  {
    "path": "src/component/handlers/edit/commands/moveSelectionForward.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type EditorState from 'EditorState';\nimport type SelectionState from 'SelectionState';\n\nconst warning = require('warning');\n\n/**\n * Given a collapsed selection, move the focus `maxDistance` forward within\n * the selected block. If the selection will go beyond the end of the block,\n * move focus to the start of the next block, but no further.\n *\n * This function is not Unicode-aware, so surrogate pairs will be treated\n * as having length 2.\n */\nfunction moveSelectionForward(\n  editorState: EditorState,\n  maxDistance: number,\n): SelectionState {\n  const selection = editorState.getSelection();\n  // Should eventually make this an invariant\n  warning(\n    selection.isCollapsed(),\n    'moveSelectionForward should only be called with a collapsed SelectionState',\n  );\n  const key = selection.getStartKey();\n  const offset = selection.getStartOffset();\n  const content = editorState.getCurrentContent();\n\n  let focusKey: ?string = key;\n  let focusOffset;\n\n  const block = content.getBlockForKey(key);\n\n  if (maxDistance > block.getText().length - offset) {\n    focusKey = content.getKeyAfter(key);\n    focusOffset = 0;\n  } else {\n    focusOffset = offset + maxDistance;\n  }\n\n  return selection.merge({focusKey, focusOffset});\n}\n\nmodule.exports = moveSelectionForward;\n"
  },
  {
    "path": "src/component/handlers/edit/commands/removeTextWithStrategy.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type ContentState from 'ContentState';\nimport type {DraftRemovalDirection} from 'DraftRemovalDirection';\nimport type EditorState from 'EditorState';\nimport type SelectionState from 'SelectionState';\n\nconst DraftModifier = require('DraftModifier');\n\nconst gkx = require('gkx');\n\nconst experimentalTreeDataSupport = gkx('draft_tree_data_support');\n\n/**\n * For a collapsed selection state, remove text based on the specified strategy.\n * If the selection state is not collapsed, remove the entire selected range.\n */\nfunction removeTextWithStrategy(\n  editorState: EditorState,\n  strategy: (editorState: EditorState) => SelectionState,\n  direction: DraftRemovalDirection,\n): ContentState {\n  const selection = editorState.getSelection();\n  const content = editorState.getCurrentContent();\n  let target = selection;\n  const anchorKey = selection.getAnchorKey();\n  const focusKey = selection.getFocusKey();\n  const anchorBlock = content.getBlockForKey(anchorKey);\n  if (experimentalTreeDataSupport) {\n    if (direction === 'forward') {\n      if (anchorKey !== focusKey) {\n        // For now we ignore forward delete across blocks,\n        // if there is demand for this we will implement it.\n        return content;\n      }\n    }\n  }\n  if (selection.isCollapsed()) {\n    if (direction === 'forward') {\n      if (editorState.isSelectionAtEndOfContent()) {\n        return content;\n      }\n      if (experimentalTreeDataSupport) {\n        const isAtEndOfBlock =\n          selection.getAnchorOffset() ===\n          content.getBlockForKey(anchorKey).getLength();\n        if (isAtEndOfBlock) {\n          const anchorBlockSibling = content.getBlockForKey(\n            anchorBlock.nextSibling,\n          );\n          if (!anchorBlockSibling || anchorBlockSibling.getLength() === 0) {\n            // For now we ignore forward delete at the end of a block,\n            // if there is demand for this we will implement it.\n            return content;\n          }\n        }\n      }\n    } else if (editorState.isSelectionAtStartOfContent()) {\n      return content;\n    }\n\n    target = strategy(editorState);\n    if (target === selection) {\n      return content;\n    }\n  }\n  return DraftModifier.removeRange(content, target, direction);\n}\n\nmodule.exports = removeTextWithStrategy;\n"
  },
  {
    "path": "src/component/handlers/edit/editOnBeforeInput.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type DraftEditor from 'DraftEditor.react';\nimport type {DraftInlineStyle} from 'DraftInlineStyle';\n\nconst DraftModifier = require('DraftModifier');\nconst EditorState = require('EditorState');\nconst UserAgent = require('UserAgent');\n\nconst editOnInput = require('editOnInput');\nconst getEntityKeyForSelection = require('getEntityKeyForSelection');\nconst isEventHandled = require('isEventHandled');\nconst isSelectionAtLeafStart = require('isSelectionAtLeafStart');\nconst nullthrows = require('nullthrows');\nconst setImmediate = require('setImmediate');\n\n// When nothing is focused, Firefox regards two characters, `'` and `/`, as\n// commands that should open and focus the \"quickfind\" search bar. This should\n// *never* happen while a contenteditable is focused, but as of v28, it\n// sometimes does, even when the keypress event target is the contenteditable.\n// This breaks the input. Special case these characters to ensure that when\n// they are typed, we prevent default on the event to make sure not to\n// trigger quickfind.\nconst FF_QUICKFIND_CHAR = \"'\";\nconst FF_QUICKFIND_LINK_CHAR = '/';\nconst isFirefox = UserAgent.isBrowser('Firefox');\nconst isIE = UserAgent.isBrowser('IE');\n\nfunction mustPreventDefaultForCharacter(character: string): boolean {\n  return (\n    isFirefox &&\n    (character == FF_QUICKFIND_CHAR || character == FF_QUICKFIND_LINK_CHAR)\n  );\n}\n\n/**\n * Replace the current selection with the specified text string, with the\n * inline style and entity key applied to the newly inserted text.\n */\nfunction replaceText(\n  editorState: EditorState,\n  text: string,\n  inlineStyle: DraftInlineStyle,\n  entityKey: ?string,\n  forceSelection: boolean,\n): EditorState {\n  const contentState = DraftModifier.replaceText(\n    editorState.getCurrentContent(),\n    editorState.getSelection(),\n    text,\n    inlineStyle,\n    entityKey,\n  );\n  return EditorState.push(\n    editorState,\n    contentState,\n    'insert-characters',\n    forceSelection,\n  );\n}\n\n/**\n * When `onBeforeInput` executes, the browser is attempting to insert a\n * character into the editor. Apply this character data to the document,\n * allowing native insertion if possible.\n *\n * Native insertion is encouraged in order to limit re-rendering and to\n * preserve spellcheck highlighting, which disappears or flashes if re-render\n * occurs on the relevant text nodes.\n */\nfunction editOnBeforeInput(\n  editor: DraftEditor,\n  e: SyntheticInputEvent<HTMLElement>,\n): void {\n  // We need this here in case this beforeInput fires before our\n  // immediate below had a chance to fire in IE (say, the user is\n  // typing fast).\n  if (isIE) {\n    if (editor._pendingStateFromBeforeInput !== undefined) {\n      editor.update(editor._pendingStateFromBeforeInput);\n      editor._pendingStateFromBeforeInput = undefined;\n    }\n  }\n\n  const editorState = editor._latestEditorState;\n\n  const chars = e.data;\n\n  // In some cases (ex: IE ideographic space insertion) no character data\n  // is provided. There's nothing to do when this happens.\n  if (!chars) {\n    return;\n  }\n\n  // Allow the top-level component to handle the insertion manually. This is\n  // useful when triggering interesting behaviors for a character insertion,\n  // Simple examples: replacing a raw text ':)' with a smile emoji or image\n  // decorator, or setting a block to be a list item after typing '- ' at the\n  // start of the block.\n  if (\n    editor.props.handleBeforeInput &&\n    isEventHandled(\n      editor.props.handleBeforeInput(chars, editorState, e.timeStamp),\n    )\n  ) {\n    e.preventDefault();\n    return;\n  }\n\n  // If selection is collapsed, conditionally allow native behavior. This\n  // reduces re-renders and preserves spellcheck highlighting. If the selection\n  // is not collapsed, we will re-render.\n  const selection = editorState.getSelection();\n  const selectionStart = selection.getStartOffset();\n  const anchorKey = selection.getAnchorKey();\n\n  if (!selection.isCollapsed()) {\n    e.preventDefault();\n    editor.update(\n      replaceText(\n        editorState,\n        chars,\n        editorState.getCurrentInlineStyle(),\n        getEntityKeyForSelection(\n          editorState.getCurrentContent(),\n          editorState.getSelection(),\n        ),\n        true,\n      ),\n    );\n    return;\n  }\n\n  let newEditorState = replaceText(\n    editorState,\n    chars,\n    editorState.getCurrentInlineStyle(),\n    getEntityKeyForSelection(\n      editorState.getCurrentContent(),\n      editorState.getSelection(),\n    ),\n    false,\n  );\n\n  // Bunch of different cases follow where we need to prevent native insertion.\n  let mustPreventNative = false;\n  if (!mustPreventNative) {\n    // Browsers tend to insert text in weird places in the DOM when typing at\n    // the start of a leaf, so we'll handle it ourselves.\n    mustPreventNative = isSelectionAtLeafStart(\n      editor._latestCommittedEditorState,\n    );\n  }\n  if (!mustPreventNative) {\n    // Let's say we have a decorator that highlights hashtags. In many cases\n    // we need to prevent native behavior and rerender ourselves --\n    // particularly, any case *except* where the inserted characters end up\n    // anywhere except exactly where you put them.\n    //\n    // Using [] to denote a decorated leaf, some examples:\n    //\n    // 1. 'hi #' and append 'f'\n    // desired rendering: 'hi [#f]'\n    // native rendering would be: 'hi #f' (incorrect)\n    //\n    // 2. 'x [#foo]' and insert '#' before 'f'\n    // desired rendering: 'x #[#foo]'\n    // native rendering would be: 'x [##foo]' (incorrect)\n    //\n    // 3. '[#foobar]' and insert ' ' between 'foo' and 'bar'\n    // desired rendering: '[#foo] bar'\n    // native rendering would be: '[#foo bar]' (incorrect)\n    //\n    // 4. '[#foo]' and delete '#' [won't use this beforeinput codepath though]\n    // desired rendering: 'foo'\n    // native rendering would be: '[foo]' (incorrect)\n    //\n    // 5. '[#foo]' and append 'b'\n    // desired rendering: '[#foob]'\n    // native rendering would be: '[#foob]'\n    // (native insertion here would be ok for decorators like simple spans,\n    // but not more complex decorators. To be safe, we need to prevent it.)\n    //\n    // It is safe to allow native insertion if and only if the full list of\n    // decorator ranges matches what we expect native insertion to give, and\n    // the range lengths have not changed. We don't need to compare the content\n    // because the only possible mutation to consider here is inserting plain\n    // text and decorators can't affect text content.\n    const oldBlockTree = editorState.getBlockTree(anchorKey);\n    const newBlockTree = newEditorState.getBlockTree(anchorKey);\n    mustPreventNative =\n      oldBlockTree.size !== newBlockTree.size ||\n      oldBlockTree.zip(newBlockTree).some(([oldLeafSet, newLeafSet]) => {\n        // selectionStart is guaranteed to be selectionEnd here\n        const oldStart = oldLeafSet.get('start');\n        const adjustedStart =\n          oldStart + (oldStart >= selectionStart ? chars.length : 0);\n        const oldEnd = oldLeafSet.get('end');\n        const adjustedEnd =\n          oldEnd + (oldEnd >= selectionStart ? chars.length : 0);\n        const newStart = newLeafSet.get('start');\n        const newEnd = newLeafSet.get('end');\n        const newDecoratorKey = newLeafSet.get('decoratorKey');\n        return (\n          // Different decorators\n          oldLeafSet.get('decoratorKey') !== newDecoratorKey ||\n          // Different number of inline styles\n          oldLeafSet.get('leaves').size !== newLeafSet.get('leaves').size ||\n          // Different effective decorator position\n          adjustedStart !== newStart ||\n          adjustedEnd !== newEnd ||\n          // Decorator already existed and its length changed\n          (newDecoratorKey != null && newEnd - newStart !== oldEnd - oldStart)\n        );\n      });\n  }\n  if (!mustPreventNative) {\n    mustPreventNative = mustPreventDefaultForCharacter(chars);\n  }\n  if (!mustPreventNative) {\n    mustPreventNative =\n      nullthrows(newEditorState.getDirectionMap()).get(anchorKey) !==\n      nullthrows(editorState.getDirectionMap()).get(anchorKey);\n  }\n\n  if (mustPreventNative) {\n    e.preventDefault();\n    newEditorState = EditorState.set(newEditorState, {\n      forceSelection: true,\n    });\n    editor.update(newEditorState);\n    return;\n  }\n\n  newEditorState = EditorState.set(newEditorState, {\n    nativelyRenderedContent: newEditorState.getCurrentContent(),\n  });\n\n  // We have newEditorState, but we just don't want to call \"editor.update\"\n  // just yet. So let's store this state updated with our change to be consumed\n  // later, after the native event occurs and the browser inserts the char.\n  // After that, when we rerender, the text we see in the DOM will already have\n  // been inserted properly.\n  //\n  editor._pendingStateFromBeforeInput = newEditorState;\n  //\n  // Part of the reason to do this is because browsers seem to change their\n  // behaviour if you preventDefault(). For example, on macOS the browser seems\n  // to believe it's no longer in a contenteditable and will change the\n  // Touch Bar on a MacBook to stop showing text suggestions.\n  //\n  // Later (presumably after we render), it realizes \"hold up, I am in a content\n  // editable, silly me\" and shows the suggestions again. But in the meantime\n  // what we get is flickering between suggestions and no suggestions. We\n  // should probably report this to Apple.\n  //\n  // Anyway, above we update our editor state if we prevent the native event, since\n  // there will be no input event after we preventDefault. Otherwise, we will\n  // do so in the \"input\" event, which fires once the text is inserted.\n  //\n  // There is one exception however: IE (what a surprise!). IE doesn't fire\n  // input events (and React doesn't polyfill them), so we never get to see\n  // how the text changed and we never get to call editor.update (which triggers\n  // onChange).\n  //\n  // To get around this, we schedule an immediate to call our usual input\n  // handler. It's important that this be an immediate so that no other random\n  // tasks from the web page get on the way (mimicking what would happen if the\n  // browser fired both the beforeInput and input events). Calling our usual\n  // input handler does the trick.\n  if (isIE) {\n    setImmediate(() => {\n      editOnInput(editor, null);\n    });\n  }\n}\n\nmodule.exports = editOnBeforeInput;\n"
  },
  {
    "path": "src/component/handlers/edit/editOnBlur.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {SelectionObject} from 'DraftDOMTypes';\nimport type DraftEditor from 'DraftEditor.react';\n\nconst EditorState = require('EditorState');\n\nconst containsNode = require('containsNode');\nconst getActiveElement = require('getActiveElement');\n\nfunction editOnBlur(editor: DraftEditor, e: SyntheticEvent<HTMLElement>): void {\n  // In a contentEditable element, when you select a range and then click\n  // another active element, this does trigger a `blur` event but will not\n  // remove the DOM selection from the contenteditable.\n  // This is consistent across all browsers, but we prefer that the editor\n  // behave like a textarea, where a `blur` event clears the DOM selection.\n  // We therefore force the issue to be certain, checking whether the active\n  // element is `body` to force it when blurring occurs within the window (as\n  // opposed to clicking to another tab or window).\n  const {ownerDocument} = e.currentTarget;\n  if (\n    !Boolean(editor.props.preserveSelectionOnBlur) &&\n    getActiveElement(ownerDocument) === ownerDocument.body\n  ) {\n    const selection: SelectionObject = ownerDocument.defaultView.getSelection();\n    const editorNode = editor.editor;\n    if (\n      selection.rangeCount === 1 &&\n      containsNode(editorNode, selection.anchorNode) &&\n      containsNode(editorNode, selection.focusNode)\n    ) {\n      selection.removeAllRanges();\n    }\n  }\n\n  const editorState = editor._latestEditorState;\n  const currentSelection = editorState.getSelection();\n  if (!currentSelection.getHasFocus()) {\n    return;\n  }\n\n  const selection = currentSelection.set('hasFocus', false);\n  editor.props.onBlur && editor.props.onBlur(e);\n  editor.update(EditorState.acceptSelection(editorState, selection));\n}\n\nmodule.exports = editOnBlur;\n"
  },
  {
    "path": "src/component/handlers/edit/editOnCompositionStart.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type DraftEditor from 'DraftEditor.react';\n\nconst EditorState = require('EditorState');\n\n/**\n * The user has begun using an IME input system. Switching to `composite` mode\n * allows handling composition input and disables other edit behavior.\n */\nfunction editOnCompositionStart(\n  editor: DraftEditor,\n  e: SyntheticEvent<>,\n): void {\n  editor.setMode('composite');\n  editor.update(\n    EditorState.set(editor._latestEditorState, {inCompositionMode: true}),\n  );\n  // Allow composition handler to interpret the compositionstart event\n  editor._onCompositionStart(e);\n}\n\nmodule.exports = editOnCompositionStart;\n"
  },
  {
    "path": "src/component/handlers/edit/editOnCopy.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type DraftEditor from 'DraftEditor.react';\n\nconst getFragmentFromSelection = require('getFragmentFromSelection');\n\n/**\n * If we have a selection, create a ContentState fragment and store\n * it in our internal clipboard. Subsequent paste events will use this\n * fragment if no external clipboard data is supplied.\n */\nfunction editOnCopy(editor: DraftEditor, e: SyntheticClipboardEvent<>): void {\n  const editorState = editor._latestEditorState;\n  const selection = editorState.getSelection();\n\n  // No selection, so there's nothing to copy.\n  if (selection.isCollapsed()) {\n    e.preventDefault();\n    return;\n  }\n\n  editor.setClipboard(getFragmentFromSelection(editor._latestEditorState));\n}\n\nmodule.exports = editOnCopy;\n"
  },
  {
    "path": "src/component/handlers/edit/editOnCut.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type DraftEditor from 'DraftEditor.react';\n\nconst DraftModifier = require('DraftModifier');\nconst EditorState = require('EditorState');\nconst Style = require('Style');\n\nconst getFragmentFromSelection = require('getFragmentFromSelection');\nconst getScrollPosition = require('getScrollPosition');\nconst isNode = require('isInstanceOfNode');\n\n/**\n * On `cut` events, native behavior is allowed to occur so that the system\n * clipboard is set properly. This means that we need to take steps to recover\n * the editor DOM state after the `cut` has occurred in order to maintain\n * control of the component.\n *\n * In addition, we can keep a copy of the removed fragment, including all\n * styles and entities, for use as an internal paste.\n */\nfunction editOnCut(editor: DraftEditor, e: SyntheticClipboardEvent<>): void {\n  const editorState = editor._latestEditorState;\n  const selection = editorState.getSelection();\n  const element = e.target;\n  let scrollPosition;\n\n  // No selection, so there's nothing to cut.\n  if (selection.isCollapsed()) {\n    e.preventDefault();\n    return;\n  }\n\n  // Track the current scroll position so that it can be forced back in place\n  // after the editor regains control of the DOM.\n  if (isNode(element)) {\n    const node: Node = (element: any);\n    scrollPosition = getScrollPosition(Style.getScrollParent(node));\n  }\n\n  const fragment = getFragmentFromSelection(editorState);\n  editor.setClipboard(fragment);\n\n  // Set `cut` mode to disable all event handling temporarily.\n  editor.setMode('cut');\n\n  // Let native `cut` behavior occur, then recover control.\n  setTimeout(() => {\n    editor.restoreEditorDOM(scrollPosition);\n    editor.exitCurrentMode();\n    editor.update(removeFragment(editorState));\n  }, 0);\n}\n\nfunction removeFragment(editorState: EditorState): EditorState {\n  const newContent = DraftModifier.removeRange(\n    editorState.getCurrentContent(),\n    editorState.getSelection(),\n    'forward',\n  );\n  return EditorState.push(editorState, newContent, 'remove-range');\n}\n\nmodule.exports = editOnCut;\n"
  },
  {
    "path": "src/component/handlers/edit/editOnDragOver.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type DraftEditor from 'DraftEditor.react';\n\n/**\n * Drag behavior has begun from outside the editor element.\n */\nfunction editOnDragOver(editor: DraftEditor, e: SyntheticDragEvent<>): void {\n  editor.setMode('drag');\n  e.preventDefault();\n}\n\nmodule.exports = editOnDragOver;\n"
  },
  {
    "path": "src/component/handlers/edit/editOnDragStart.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type DraftEditor from 'DraftEditor.react';\n\n/**\n * A `dragstart` event has begun within the text editor component.\n */\nfunction editOnDragStart(editor: DraftEditor): void {\n  editor._internalDrag = true;\n  editor.setMode('drag');\n}\n\nmodule.exports = editOnDragStart;\n"
  },
  {
    "path": "src/component/handlers/edit/editOnFocus.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type DraftEditor from 'DraftEditor.react';\n\nconst EditorState = require('EditorState');\nconst UserAgent = require('UserAgent');\n\nfunction editOnFocus(editor: DraftEditor, e: SyntheticFocusEvent<>): void {\n  const editorState = editor._latestEditorState;\n  const currentSelection = editorState.getSelection();\n  if (currentSelection.getHasFocus()) {\n    return;\n  }\n\n  const selection = currentSelection.set('hasFocus', true);\n  editor.props.onFocus && editor.props.onFocus(e);\n\n  // When the tab containing this text editor is hidden and the user does a\n  // find-in-page in a _different_ tab, Chrome on Mac likes to forget what the\n  // selection was right after sending this focus event and (if you let it)\n  // moves the cursor back to the beginning of the editor, so we force the\n  // selection here instead of simply accepting it in order to preserve the\n  // old cursor position. See https://crbug.com/540004.\n  // But it looks like this is fixed in Chrome 60.0.3081.0.\n  // Other browsers also don't have this bug, so we prefer to acceptSelection\n  // when possible, to ensure that unfocusing and refocusing a Draft editor\n  // doesn't preserve the selection, matching how textareas work.\n  if (UserAgent.isBrowser('Chrome < 60.0.3081.0')) {\n    editor.update(EditorState.forceSelection(editorState, selection));\n  } else {\n    editor.update(EditorState.acceptSelection(editorState, selection));\n  }\n}\n\nmodule.exports = editOnFocus;\n"
  },
  {
    "path": "src/component/handlers/edit/editOnInput.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {SelectionObject} from 'DraftDOMTypes';\nimport type DraftEditor from 'DraftEditor.react';\n\nconst DraftModifier = require('DraftModifier');\nconst DraftOffsetKey = require('DraftOffsetKey');\nconst EditorState = require('EditorState');\nconst UserAgent = require('UserAgent');\n\nconst {notEmptyKey} = require('draftKeyUtils');\nconst findAncestorOffsetKey = require('findAncestorOffsetKey');\nconst keyCommandPlainBackspace = require('keyCommandPlainBackspace');\nconst nullthrows = require('nullthrows');\n\nconst isGecko = UserAgent.isEngine('Gecko');\n\nconst DOUBLE_NEWLINE = '\\n\\n';\n\nfunction onInputType(inputType: string, editorState: EditorState): EditorState {\n  switch (inputType) {\n    case 'deleteContentBackward':\n      return keyCommandPlainBackspace(editorState);\n  }\n  return editorState;\n}\n\n/**\n * This function serves two purposes\n *\n * 1. To update the editorState and call onChange method with the new\n * editorState. This editorState is calculated in editOnBeforeInput but the\n * onChange method is not called with the new state until this method does it.\n * It is done to handle a specific case where certain character inputs might\n * be replaced with something else. E.g. snippets ('rc' might be replaced\n * with boilerplate code for react component). More information on the\n * exact problem can be found here -\n * https://github.com/facebook/draft-js/commit/07892ba479bd4dfc6afd1e0ed179aaf51cd138b1\n *\n * 2. intended to handle spellcheck and autocorrect changes,\n * which occur in the DOM natively without any opportunity to observe or\n * interpret the changes before they occur.\n *\n * The `input` event fires in contentEditable elements reliably for non-IE\n * browsers, immediately after changes occur to the editor DOM. Since our other\n * handlers override or otherwise handle cover other varieties of text input,\n * the DOM state should match the model in all controlled input cases. Thus,\n * when an `input` change leads to a DOM/model mismatch, the change should be\n * due to a spellcheck change, and we can incorporate it into our model.\n */\nfunction editOnInput(editor: DraftEditor, event: ?SyntheticInputEvent<>): void {\n  // This will happen for most simple insertions. The new state is already\n  // computed. Let's just call \"editor.update\". Things should match nicely so\n  // this function will exit below where we check \"domText === modelText\".\n  if (editor._pendingStateFromBeforeInput !== undefined) {\n    editor.update(editor._pendingStateFromBeforeInput);\n    editor._pendingStateFromBeforeInput = undefined;\n  }\n\n  // at this point editor is not null for sure (after input)\n  const castedEditorElement: HTMLElement = (editor.editor: any);\n  const domSelection: SelectionObject =\n    castedEditorElement.ownerDocument.defaultView.getSelection();\n\n  const {anchorNode, isCollapsed} = domSelection;\n  const isNotTextOrElementNode =\n    anchorNode?.nodeType !== Node.TEXT_NODE &&\n    anchorNode?.nodeType !== Node.ELEMENT_NODE;\n\n  if (anchorNode == null || isNotTextOrElementNode) {\n    // TODO: (t16149272) figure out context for this change\n    return;\n  }\n\n  if (\n    anchorNode.nodeType === Node.TEXT_NODE &&\n    (anchorNode.previousSibling !== null || anchorNode.nextSibling !== null)\n  ) {\n    // When typing at the beginning of a visual line, Chrome splits the text\n    // nodes into two. Why? No one knows. This commit is suspicious:\n    // https://chromium.googlesource.com/chromium/src/+/a3b600981286b135632371477f902214c55a1724\n    // To work around, we'll merge the sibling text nodes back into this one.\n    const span = anchorNode.parentNode;\n    if (span == null) {\n      // Handle null-parent case.\n      return;\n    }\n    anchorNode.nodeValue = span.textContent;\n    for (\n      let child = span.firstChild;\n      child != null;\n      child = child.nextSibling\n    ) {\n      if (child !== anchorNode) {\n        span.removeChild(child);\n      }\n    }\n  }\n\n  let domText = anchorNode.textContent;\n  const editorState = editor._latestEditorState;\n  const offsetKey = nullthrows(findAncestorOffsetKey(anchorNode));\n  const {blockKey, decoratorKey, leafKey} = DraftOffsetKey.decode(offsetKey);\n\n  const {start, end} = editorState\n    .getBlockTree(blockKey)\n    .getIn([decoratorKey, 'leaves', leafKey]);\n\n  const content = editorState.getCurrentContent();\n  const block = content.getBlockForKey(blockKey);\n  const modelText = block.getText().slice(start, end);\n\n  // Special-case soft newlines here. If the DOM text ends in a soft newline,\n  // we will have manually inserted an extra soft newline in DraftEditorLeaf.\n  // We want to remove this extra newline for the purpose of our comparison\n  // of DOM and model text.\n  if (domText.endsWith(DOUBLE_NEWLINE)) {\n    domText = domText.slice(0, -1);\n  }\n\n  // No change -- the DOM is up to date. Nothing to do here.\n  if (domText === modelText) {\n    // This can be buggy for some Android keyboards because they don't fire\n    // standard onkeydown/pressed events and only fired editOnInput\n    // so domText is already changed by the browser and ends up being equal\n    // to modelText unexpectedly.\n    // Newest versions of Android support the dom-inputevent-inputtype\n    // and we can use the `inputType` to properly apply the state changes.\n\n    /* $FlowFixMe[prop-missing] inputType is only defined on a draft of a\n     * standard. https://w3c.github.io/input-events/#dom-inputevent-inputtype\n     */\n    const inputType = event ? event.nativeEvent.inputType : undefined;\n    if (inputType) {\n      const newEditorState = onInputType(inputType, editorState);\n      if (newEditorState !== editorState) {\n        editor.restoreEditorDOM();\n        editor.update(newEditorState);\n        return;\n      }\n    }\n    return;\n  }\n\n  const selection = editorState.getSelection();\n\n  // We'll replace the entire leaf with the text content of the target.\n  const targetRange = selection.merge({\n    anchorOffset: start,\n    focusOffset: end,\n    isBackward: false,\n  });\n\n  const entityKey = block.getEntityAt(start);\n  const entity = notEmptyKey(entityKey) ? content.getEntity(entityKey) : null;\n  const entityType = entity != null ? entity.getMutability() : null;\n  const preserveEntity = entityType === 'MUTABLE';\n\n  // Immutable or segmented entities cannot properly be handled by the\n  // default browser undo, so we have to use a different change type to\n  // force using our internal undo method instead of falling through to the\n  // native browser undo.\n  const changeType = preserveEntity ? 'spellcheck-change' : 'apply-entity';\n\n  const newContent = DraftModifier.replaceText(\n    content,\n    targetRange,\n    domText,\n    block.getInlineStyleAt(start),\n    preserveEntity ? block.getEntityAt(start) : null,\n  );\n\n  let anchorOffset, focusOffset, startOffset, endOffset;\n\n  const isDeleteWordForward =\n    // $FlowFixMe[prop-missing] Flow doesn't know if can be an InputEvent w/ inputType\n    event?.nativeEvent?.inputType === 'deleteWordForward';\n\n  // Adjust our selection if appropriate. If we're deleting the word forward, we\n  // don't do this, since we want to stay at the same offset.\n  if (isGecko && !isDeleteWordForward) {\n    // Firefox selection does not change while the context menu is open, so\n    // we preserve the anchor and focus values of the DOM selection.\n    anchorOffset = domSelection.anchorOffset;\n    focusOffset = domSelection.focusOffset;\n    startOffset = start + Math.min(anchorOffset, focusOffset);\n    endOffset = startOffset + Math.abs(anchorOffset - focusOffset);\n    anchorOffset = startOffset;\n    focusOffset = endOffset;\n  } else if (!isDeleteWordForward) {\n    // Browsers other than Firefox may adjust DOM selection while the context\n    // menu is open, and Safari autocorrect is prone to providing an inaccurate\n    // DOM selection. Don't trust it. Instead, use our existing SelectionState\n    // and adjust it based on the number of characters changed during the\n    // mutation.\n    const charDelta = domText.length - modelText.length;\n    startOffset = selection.getStartOffset();\n    endOffset = selection.getEndOffset();\n\n    anchorOffset = isCollapsed ? endOffset + charDelta : startOffset;\n    focusOffset = endOffset + charDelta;\n  }\n\n  // Segmented entities are completely or partially removed when their\n  // text content changes. For this case we do not want any text to be selected\n  // after the change, so we are not merging the selection.\n  const contentWithAdjustedDOMSelection = newContent.merge({\n    selectionBefore: content.getSelectionAfter(),\n    selectionAfter: selection.merge({anchorOffset, focusOffset}),\n  });\n\n  editor.update(\n    EditorState.push(editorState, contentWithAdjustedDOMSelection, changeType),\n  );\n}\n\nmodule.exports = editOnInput;\n"
  },
  {
    "path": "src/component/handlers/edit/editOnKeyDown.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type DraftEditor from 'DraftEditor.react';\nimport type {DraftEditorCommand} from 'DraftEditorCommand';\n\nconst DraftModifier = require('DraftModifier');\nconst EditorState = require('EditorState');\nconst KeyBindingUtil = require('KeyBindingUtil');\nconst Keys = require('Keys');\nconst SecondaryClipboard = require('SecondaryClipboard');\nconst UserAgent = require('UserAgent');\n\nconst isEventHandled = require('isEventHandled');\nconst keyCommandBackspaceToStartOfLine = require('keyCommandBackspaceToStartOfLine');\nconst keyCommandBackspaceWord = require('keyCommandBackspaceWord');\nconst keyCommandDeleteWord = require('keyCommandDeleteWord');\nconst keyCommandInsertNewline = require('keyCommandInsertNewline');\nconst keyCommandMoveSelectionToEndOfBlock = require('keyCommandMoveSelectionToEndOfBlock');\nconst keyCommandMoveSelectionToStartOfBlock = require('keyCommandMoveSelectionToStartOfBlock');\nconst keyCommandPlainBackspace = require('keyCommandPlainBackspace');\nconst keyCommandPlainDelete = require('keyCommandPlainDelete');\nconst keyCommandTransposeCharacters = require('keyCommandTransposeCharacters');\nconst keyCommandUndo = require('keyCommandUndo');\n\nconst {isOptionKeyCommand} = KeyBindingUtil;\nconst isChrome = UserAgent.isBrowser('Chrome');\n\n/**\n * Map a `DraftEditorCommand` command value to a corresponding function.\n */\nfunction onKeyCommand(\n  command: DraftEditorCommand | string,\n  editorState: EditorState,\n  e: SyntheticKeyboardEvent<HTMLElement>,\n): EditorState {\n  switch (command) {\n    case 'redo':\n      return EditorState.redo(editorState);\n    case 'delete':\n      return keyCommandPlainDelete(editorState);\n    case 'delete-word':\n      return keyCommandDeleteWord(editorState);\n    case 'backspace':\n      return keyCommandPlainBackspace(editorState);\n    case 'backspace-word':\n      return keyCommandBackspaceWord(editorState);\n    case 'backspace-to-start-of-line':\n      return keyCommandBackspaceToStartOfLine(editorState, e);\n    case 'split-block':\n      return keyCommandInsertNewline(editorState);\n    case 'transpose-characters':\n      return keyCommandTransposeCharacters(editorState);\n    case 'move-selection-to-start-of-block':\n      return keyCommandMoveSelectionToStartOfBlock(editorState);\n    case 'move-selection-to-end-of-block':\n      return keyCommandMoveSelectionToEndOfBlock(editorState);\n    case 'secondary-cut':\n      return SecondaryClipboard.cut(editorState);\n    case 'secondary-paste':\n      return SecondaryClipboard.paste(editorState);\n    default:\n      return editorState;\n  }\n}\n\n/**\n * Intercept keydown behavior to handle keys and commands manually, if desired.\n *\n * Keydown combinations may be mapped to `DraftCommand` values, which may\n * correspond to command functions that modify the editor or its contents.\n *\n * See `getDefaultKeyBinding` for defaults. Alternatively, the top-level\n * component may provide a custom mapping via the `keyBindingFn` prop.\n */\nfunction editOnKeyDown(\n  editor: DraftEditor,\n  e: SyntheticKeyboardEvent<HTMLElement>,\n): void {\n  const keyCode = e.which;\n  const editorState = editor._latestEditorState;\n  function callDeprecatedHandler(\n    handlerName:\n      | 'onDownArrow'\n      | 'onEscape'\n      | 'onLeftArrow'\n      | 'onRightArrow'\n      | 'onTab'\n      | 'onUpArrow',\n  ): boolean {\n    const deprecatedHandler = editor.props[handlerName];\n    if (deprecatedHandler) {\n      deprecatedHandler(e);\n      return true;\n    } else {\n      return false;\n    }\n  }\n  switch (keyCode) {\n    case Keys.RETURN:\n      e.preventDefault();\n      // The top-level component may manually handle newline insertion. If\n      // no special handling is performed, fall through to command handling.\n      if (\n        editor.props.handleReturn &&\n        isEventHandled(editor.props.handleReturn(e, editorState))\n      ) {\n        return;\n      }\n      break;\n    case Keys.ESC:\n      e.preventDefault();\n      if (callDeprecatedHandler('onEscape')) {\n        return;\n      }\n      break;\n    case Keys.TAB:\n      if (callDeprecatedHandler('onTab')) {\n        return;\n      }\n      break;\n    case Keys.UP:\n      if (callDeprecatedHandler('onUpArrow')) {\n        return;\n      }\n      break;\n    case Keys.RIGHT:\n      if (callDeprecatedHandler('onRightArrow')) {\n        return;\n      }\n      break;\n    case Keys.DOWN:\n      if (callDeprecatedHandler('onDownArrow')) {\n        return;\n      }\n      break;\n    case Keys.LEFT:\n      if (callDeprecatedHandler('onLeftArrow')) {\n        return;\n      }\n      break;\n    case Keys.SPACE:\n      // Prevent Chrome on OSX behavior where option + space scrolls.\n      if (isChrome && isOptionKeyCommand(e)) {\n        e.preventDefault();\n      }\n  }\n\n  const command = editor.props.keyBindingFn(e);\n\n  // If no command is specified, allow keydown event to continue.\n  if (command == null || command === '') {\n    if (keyCode === Keys.SPACE && isChrome && isOptionKeyCommand(e)) {\n      // The default keydown event has already been prevented in order to stop\n      // Chrome from scrolling. Insert a nbsp into the editor as OSX would for\n      // other browsers.\n      const contentState = DraftModifier.replaceText(\n        editorState.getCurrentContent(),\n        editorState.getSelection(),\n        '\\u00a0',\n      );\n      editor.update(\n        EditorState.push(editorState, contentState, 'insert-characters'),\n      );\n    }\n    return;\n  }\n\n  if (command === 'undo') {\n    // Since undo requires some special updating behavior to keep the editor\n    // in sync, handle it separately.\n    keyCommandUndo(e, editorState, editor.update);\n    return;\n  }\n\n  // At this point, we know that we're handling a command of some kind, so\n  // we don't want to insert a character following the keydown.\n  e.preventDefault();\n\n  // Allow components higher up the tree to handle the command first.\n  if (\n    editor.props.handleKeyCommand &&\n    isEventHandled(\n      editor.props.handleKeyCommand(command, editorState, e.timeStamp),\n    )\n  ) {\n    return;\n  }\n\n  const newState = onKeyCommand(command, editorState, e);\n  if (newState !== editorState) {\n    editor.update(newState);\n  }\n}\n\nmodule.exports = editOnKeyDown;\n"
  },
  {
    "path": "src/component/handlers/edit/editOnPaste.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockMap} from 'BlockMap';\nimport type DraftEditor from 'DraftEditor.react';\nimport type {EntityMap} from 'EntityMap';\n\nconst BlockMapBuilder = require('BlockMapBuilder');\nconst CharacterMetadata = require('CharacterMetadata');\nconst ContentState = require('ContentState');\nconst DataTransfer = require('DataTransfer');\nconst DraftModifier = require('DraftModifier');\nconst DraftPasteProcessor = require('DraftPasteProcessor');\nconst EditorState = require('EditorState');\nconst RichTextEditorUtil = require('RichTextEditorUtil');\n\nconst getEntityKeyForSelection = require('getEntityKeyForSelection');\nconst getTextContentFromFiles = require('getTextContentFromFiles');\nconst isEventHandled = require('isEventHandled');\nconst splitTextIntoTextBlocks = require('splitTextIntoTextBlocks');\n\n/**\n * Paste content.\n */\nfunction editOnPaste(editor: DraftEditor, e: SyntheticClipboardEvent<>): void {\n  e.preventDefault();\n  const data = new DataTransfer(e.clipboardData);\n\n  // Get files, unless this is likely to be a string the user wants inline.\n  if (!data.isRichText()) {\n    const files: Array<Blob> = (data.getFiles(): any);\n    const defaultFileText = data.getText();\n    if (files.length > 0) {\n      // Allow customized paste handling for images, etc. Otherwise, fall\n      // through to insert text contents into the editor.\n      if (\n        editor.props.handlePastedFiles &&\n        isEventHandled(editor.props.handlePastedFiles(files))\n      ) {\n        return;\n      }\n\n      /* $FlowFixMe[incompatible-call] This comment suppresses an error found\n       * DataTransfer was typed. getFiles() returns an array of <Files extends\n       * Blob>, not Blob */\n      getTextContentFromFiles(files, (/*string*/ fileText) => {\n        fileText = fileText || defaultFileText;\n        if (!fileText) {\n          return;\n        }\n\n        const editorState = editor._latestEditorState;\n        const blocks = splitTextIntoTextBlocks(fileText);\n        const character = CharacterMetadata.create({\n          style: editorState.getCurrentInlineStyle(),\n          entity: getEntityKeyForSelection(\n            editorState.getCurrentContent(),\n            editorState.getSelection(),\n          ),\n        });\n        const currentBlockType =\n          RichTextEditorUtil.getCurrentBlockType(editorState);\n\n        const text = DraftPasteProcessor.processText(\n          blocks,\n          character,\n          currentBlockType,\n        );\n        const fragment = BlockMapBuilder.createFromArray(text);\n\n        const withInsertedText = DraftModifier.replaceWithFragment(\n          editorState.getCurrentContent(),\n          editorState.getSelection(),\n          fragment,\n        );\n\n        editor.update(\n          EditorState.push(editorState, withInsertedText, 'insert-fragment'),\n        );\n      });\n\n      return;\n    }\n  }\n\n  let textBlocks: Array<string> = [];\n  let text: string = (data.getText(): any);\n  let html: string = (data.getHTML(): any);\n  const editorState = editor._latestEditorState;\n\n  if (editor.props.formatPastedText) {\n    const {text: formattedText, html: formattedHtml} =\n      editor.props.formatPastedText(text, html);\n    text = formattedText;\n    html = ((formattedHtml: any): string);\n  }\n\n  if (text) {\n    textBlocks = splitTextIntoTextBlocks(text);\n  }\n\n  let handleInternalPaste: ?() => void = null;\n\n  if (!editor.props.stripPastedStyles) {\n    // If the text from the paste event is rich content that matches what we\n    // already have on the internal clipboard, assume that we should just use\n    // the clipboard fragment for the paste. This will allow us to preserve\n    // styling and entities, if any are present. Note that newlines are\n    // stripped during comparison -- this is because copy/paste within the\n    // editor in Firefox and IE will not include empty lines. The resulting\n    // paste will preserve the newlines correctly.\n    const internalClipboard = editor.getClipboard();\n    if (\n      !editor.props.formatPastedText &&\n      data.isRichText() &&\n      internalClipboard\n    ) {\n      if (\n        // If the editorKey is present in the pasted HTML, it should be safe to\n        // assume this is an internal paste.\n        html?.indexOf(editor.getEditorKey()) !== -1 ||\n        // The copy may have been made within a single block, in which case the\n        // editor key won't be part of the paste. In this case, just check\n        // whether the pasted text matches the internal clipboard.\n        (textBlocks.length === 1 &&\n          internalClipboard.size === 1 &&\n          internalClipboard.first().getText() === text)\n      ) {\n        handleInternalPaste = () =>\n          editor.update(\n            insertFragment(editor._latestEditorState, internalClipboard),\n          );\n      }\n    } else if (\n      internalClipboard &&\n      data.types.includes('com.apple.webarchive') &&\n      !data.types.includes('text/html') &&\n      areTextBlocksAndClipboardEqual(textBlocks, internalClipboard)\n    ) {\n      // Safari does not properly store text/html in some cases.\n      // Use the internalClipboard if present and equal to what is on\n      // the clipboard. See https://bugs.webkit.org/show_bug.cgi?id=19893.\n      handleInternalPaste = () =>\n        editor.update(\n          insertFragment(editor._latestEditorState, internalClipboard),\n        );\n    }\n\n    if (\n      editor.props.handlePastedText &&\n      isEventHandled(\n        editor.props.handlePastedText(\n          text,\n          html,\n          editorState,\n          handleInternalPaste != null,\n        ),\n      )\n    ) {\n      return;\n    }\n\n    if (handleInternalPaste != null) {\n      handleInternalPaste();\n      return;\n    }\n\n    // If there is html paste data, try to parse that.\n    if (html) {\n      const htmlFragment = DraftPasteProcessor.processHTML(\n        html,\n        editor.props.blockRenderMap,\n      );\n      if (htmlFragment) {\n        const {contentBlocks, entityMap} = htmlFragment;\n        if (contentBlocks) {\n          const htmlMap = BlockMapBuilder.createFromArray(contentBlocks);\n          editor.update(\n            insertFragment(editor._latestEditorState, htmlMap, entityMap),\n          );\n          return;\n        }\n      }\n    }\n\n    // Otherwise, create a new fragment from our pasted text. Also\n    // empty the internal clipboard, since it's no longer valid.\n    editor.setClipboard(null);\n  }\n\n  if (textBlocks.length) {\n    const character = CharacterMetadata.create({\n      style: editorState.getCurrentInlineStyle(),\n      entity: getEntityKeyForSelection(\n        editorState.getCurrentContent(),\n        editorState.getSelection(),\n      ),\n    });\n\n    const currentBlockType =\n      RichTextEditorUtil.getCurrentBlockType(editorState);\n\n    const textFragment = DraftPasteProcessor.processText(\n      textBlocks,\n      character,\n      currentBlockType,\n    );\n\n    const textMap = BlockMapBuilder.createFromArray(textFragment);\n    editor.update(insertFragment(editor._latestEditorState, textMap));\n  }\n}\n\nfunction insertFragment(\n  editorState: EditorState,\n  fragment: BlockMap,\n  entityMap: ?EntityMap,\n): EditorState {\n  const newContent = DraftModifier.replaceWithFragment(\n    editorState.getCurrentContent(),\n    editorState.getSelection(),\n    fragment,\n  );\n\n  const newEntityMap = entityMap\n    ? ContentState.mergeEntityMaps(newContent.getAllEntities(), entityMap)\n    : newContent.getAllEntities();\n\n  return EditorState.push(\n    editorState,\n    newContent.setEntityMap(newEntityMap),\n    'insert-fragment',\n  );\n}\n\nfunction areTextBlocksAndClipboardEqual(\n  textBlocks: Array<string>,\n  blockMap: BlockMap,\n): boolean {\n  return (\n    textBlocks.length === blockMap.size &&\n    blockMap.valueSeq().every((block, ii) => block.getText() === textBlocks[ii])\n  );\n}\n\nmodule.exports = editOnPaste;\n"
  },
  {
    "path": "src/component/handlers/edit/editOnSelect.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type DraftEditor from 'DraftEditor.react';\n\nconst DraftJsDebugLogging = require('DraftJsDebugLogging');\nconst EditorState = require('EditorState');\n\nconst getContentEditableContainer = require('getContentEditableContainer');\nconst getDraftEditorSelection = require('getDraftEditorSelection');\n\nfunction editOnSelect(editor: DraftEditor): void {\n  if (\n    editor._blockSelectEvents ||\n    editor._latestEditorState !== editor.props.editorState\n  ) {\n    if (editor._blockSelectEvents) {\n      const editorState = editor.props.editorState;\n      const selectionState = editorState.getSelection();\n      DraftJsDebugLogging.logBlockedSelectionEvent({\n        // For now I don't think we need any other info\n        anonymizedDom: 'N/A',\n        extraParams: JSON.stringify({stacktrace: new Error().stack}),\n        selectionState: JSON.stringify(selectionState.toJS()),\n      });\n    }\n    return;\n  }\n\n  let editorState: EditorState = editor.props.editorState;\n  const documentSelection = getDraftEditorSelection(\n    editorState,\n    getContentEditableContainer(editor),\n  );\n  const updatedSelectionState = documentSelection.selectionState;\n\n  if (updatedSelectionState !== editorState.getSelection()) {\n    if (documentSelection.needsRecovery) {\n      editorState = EditorState.forceSelection(\n        editorState,\n        updatedSelectionState,\n      );\n    } else {\n      editorState = EditorState.acceptSelection(\n        editorState,\n        updatedSelectionState,\n      );\n    }\n    editor.update(editorState);\n  }\n}\n\nmodule.exports = editOnSelect;\n"
  },
  {
    "path": "src/component/handlers/edit/getFragmentFromSelection.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockMap} from 'BlockMap';\nimport type EditorState from 'EditorState';\n\nconst getContentStateFragment = require('getContentStateFragment');\n\nfunction getFragmentFromSelection(editorState: EditorState): ?BlockMap {\n  const selectionState = editorState.getSelection();\n\n  if (selectionState.isCollapsed()) {\n    return null;\n  }\n\n  return getContentStateFragment(\n    editorState.getCurrentContent(),\n    selectionState,\n  );\n}\n\nmodule.exports = getFragmentFromSelection;\n"
  },
  {
    "path": "src/component/selection/DOMDerivedSelection.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type SelectionState from 'SelectionState';\n\nexport type DOMDerivedSelection = {\n  selectionState: SelectionState,\n  needsRecovery: boolean,\n};\n"
  },
  {
    "path": "src/component/selection/DraftOffsetKey.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {DraftOffsetKeyPath} from 'DraftOffsetKeyPath';\n\nconst KEY_DELIMITER = '-';\n\nconst DraftOffsetKey = {\n  encode(blockKey: string, decoratorKey: number, leafKey: number): string {\n    return blockKey + KEY_DELIMITER + decoratorKey + KEY_DELIMITER + leafKey;\n  },\n\n  decode(offsetKey: string): DraftOffsetKeyPath {\n    // Extracts the last two parts of offsetKey and captures the rest in blockKeyParts\n    const [leafKey, decoratorKey, ...blockKeyParts] = offsetKey\n      .split(KEY_DELIMITER)\n      .reverse();\n\n    return {\n      // Recomposes the parts of blockKey after reversing them\n      blockKey: blockKeyParts.reverse().join(KEY_DELIMITER),\n      decoratorKey: parseInt(decoratorKey, 10),\n      leafKey: parseInt(leafKey, 10),\n    };\n  },\n};\n\nmodule.exports = DraftOffsetKey;\n"
  },
  {
    "path": "src/component/selection/DraftOffsetKeyPath.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nexport type DraftOffsetKeyPath = {\n  blockKey: string,\n  decoratorKey: number,\n  leafKey: number,\n};\n"
  },
  {
    "path": "src/component/selection/__tests__/DraftOffsetKey-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\nconst DraftOffsetKey = require('DraftOffsetKey');\n\ntest('decodes offset key with no delimiter', () => {\n  expect(DraftOffsetKey.decode('key-0-1')).toMatchSnapshot();\n});\n\ntest('decodes offset key with delimiter in between', () => {\n  expect(DraftOffsetKey.decode('key-with-delimiter-0-1')).toMatchSnapshot();\n});\n\ntest('decodes offset key with delimiter at the beginning', () => {\n  expect(DraftOffsetKey.decode('-key-0-1')).toMatchSnapshot();\n});\n\ntest('decodes offset key with delimiter at the end', () => {\n  expect(DraftOffsetKey.decode('key--0-1')).toMatchSnapshot();\n});\n"
  },
  {
    "path": "src/component/selection/__tests__/__snapshots__/DraftOffsetKey-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`decodes offset key with delimiter at the beginning 1`] = `\nObject {\n  \"blockKey\": \"-key\",\n  \"decoratorKey\": 0,\n  \"leafKey\": 1,\n}\n`;\n\nexports[`decodes offset key with delimiter at the end 1`] = `\nObject {\n  \"blockKey\": \"key-\",\n  \"decoratorKey\": 0,\n  \"leafKey\": 1,\n}\n`;\n\nexports[`decodes offset key with delimiter in between 1`] = `\nObject {\n  \"blockKey\": \"key-with-delimiter\",\n  \"decoratorKey\": 0,\n  \"leafKey\": 1,\n}\n`;\n\nexports[`decodes offset key with no delimiter 1`] = `\nObject {\n  \"blockKey\": \"key\",\n  \"decoratorKey\": 0,\n  \"leafKey\": 1,\n}\n`;\n"
  },
  {
    "path": "src/component/selection/__tests__/__snapshots__/getDraftEditorSelection-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`begins at nested text node zero, ends at end of nested block 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"b\",\n    \"focusOffset\": 4,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`begins at text node zero, ends at end of block 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 19,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`begins within nested text node, ends at end of nested block 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 2,\n    \"focusKey\": \"b\",\n    \"focusOffset\": 4,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`begins within text node, ends at end of block 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 5,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 19,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`contains an entire leaf 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"c\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 7,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`contains an entire nested leaf 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"d\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 5,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`does the crazy stuff described above 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 12,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`does the crazy stuff described above with nested blocks 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 5,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`extends from head of one nested node to end of another nested node 1`] = `\nObject {\n  \"needsRecovery\": false,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 5,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`extends from head of one node to end of another 1`] = `\nObject {\n  \"needsRecovery\": false,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"b\",\n    \"focusOffset\": 7,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`from start of one block to end of other block 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 7,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`from start of one block to start of another 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`from start of one nestd block to end of other nested block 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 5,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`from start of one nested block to start of another 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`goes from end of one nested block to end of other nested block 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 4,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 5,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`goes from end of one to end of other block 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 19,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 12,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`goes from start of one block to end of other block 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 12,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`goes from start of one block to start of other 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`goes from start of one nested block to end of other nested block 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 5,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`goes from start of one nested block to start of other 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`goes from within one block to within another block 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 19,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 7,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`goes from within one nested block to within another nested block 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 4,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 5,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is a reversed nested text-to-leaf selection 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"d\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"b\",\n    \"focusOffset\": 2,\n    \"hasFocus\": false,\n    \"isBackward\": true,\n  },\n}\n`;\n\nexports[`is a reversed selection across multiple nested text nodes 1`] = `\nObject {\n  \"needsRecovery\": false,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 2,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 3,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is a reversed selection across multiple text nodes 1`] = `\nObject {\n  \"needsRecovery\": false,\n  \"selectionState\": Object {\n    \"anchorKey\": \"c\",\n    \"anchorOffset\": 4,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 6,\n    \"hasFocus\": false,\n    \"isBackward\": true,\n  },\n}\n`;\n\nexports[`is a reversed text-to-leaf selection 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"c\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 4,\n    \"hasFocus\": false,\n    \"isBackward\": true,\n  },\n}\n`;\n\nexports[`is a reversed text-to-leaf-child selection 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"c\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 4,\n    \"hasFocus\": false,\n    \"isBackward\": true,\n  },\n}\n`;\n\nexports[`is a reversed text-to-leaf-child selection of nested node 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"d\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"b\",\n    \"focusOffset\": 4,\n    \"hasFocus\": false,\n    \"isBackward\": true,\n  },\n}\n`;\n\nexports[`is collapsed at end at nested single block 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 4,\n    \"focusKey\": \"b\",\n    \"focusOffset\": 4,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is collapsed at end at single block 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 19,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 19,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is collapsed at end of nested single span 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 4,\n    \"focusKey\": \"b\",\n    \"focusOffset\": 4,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is collapsed at end of single span 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 10,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 10,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is collapsed at end with full selection 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"c\",\n    \"anchorOffset\": 12,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 12,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is collapsed at end with full selection with nested blocks 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"d\",\n    \"anchorOffset\": 5,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 5,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is collapsed at start at nested single block 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"b\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is collapsed at start at single block 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is collapsed at start of nested single span 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"b\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is collapsed at start of single span 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is collapsed at start with full selection 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is collapsed at start with full selection with nested blocks 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is collapsed at the end of a child 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 19,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 19,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is collapsed at the end of a nested child 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 4,\n    \"focusKey\": \"b\",\n    \"focusOffset\": 4,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is collapsed at the start of the contents 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is collapsed at the start of the contents with nesting blocks 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is completely selected 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 12,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is completely selected with nested blocks 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 5,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is contains multiple children 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 12,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is contains multiple nested children 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 5,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is entirely selected 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 19,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is entirely selected with nested blocks 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"b\",\n    \"focusOffset\": 4,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`is reversed from above 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"c\",\n    \"anchorOffset\": 12,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": true,\n  },\n}\n`;\n\nexports[`is reversed from above nested blocks 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"d\",\n    \"anchorOffset\": 5,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": true,\n  },\n}\n`;\n\nexports[`is reversed from the first case 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 19,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": true,\n  },\n}\n`;\n\nexports[`is reversed from the first nested case 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 4,\n    \"focusKey\": \"b\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": true,\n  },\n}\n`;\n\nexports[`is reversed on entire leaf 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"c\",\n    \"anchorOffset\": 7,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": true,\n  },\n}\n`;\n\nexports[`is reversed on nested entire leaf 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"d\",\n    \"anchorOffset\": 5,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": true,\n  },\n}\n`;\n\nexports[`is the same as above but nested and reversed 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"d\",\n    \"anchorOffset\": 5,\n    \"focusKey\": \"b\",\n    \"focusOffset\": 4,\n    \"hasFocus\": false,\n    \"isBackward\": true,\n  },\n}\n`;\n\nexports[`is the same as above but reversed 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"c\",\n    \"anchorOffset\": 7,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 19,\n    \"hasFocus\": false,\n    \"isBackward\": true,\n  },\n}\n`;\n\nexports[`must find offsets for non-collapsed selection 1`] = `\nObject {\n  \"needsRecovery\": false,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 1,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 6,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`must find offsets for non-collapsed selection of nested node 1`] = `\nObject {\n  \"needsRecovery\": false,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 1,\n    \"focusKey\": \"b\",\n    \"focusOffset\": 2,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`must find offsets for reversed selection 1`] = `\nObject {\n  \"needsRecovery\": false,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 6,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 1,\n    \"hasFocus\": false,\n    \"isBackward\": true,\n  },\n}\n`;\n\nexports[`must find offsets for reversed selection of nested node 1`] = `\nObject {\n  \"needsRecovery\": false,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 2,\n    \"focusKey\": \"b\",\n    \"focusOffset\": 1,\n    \"hasFocus\": false,\n    \"isBackward\": true,\n  },\n}\n`;\n\nexports[`must find offsets for selection on entire text node 1`] = `\nObject {\n  \"needsRecovery\": false,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 10,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`must find offsets for selection on entire text node of nested node 1`] = `\nObject {\n  \"needsRecovery\": false,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"b\",\n    \"focusOffset\": 4,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`must find offsets when collapsed at end 1`] = `\nObject {\n  \"needsRecovery\": false,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 10,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 10,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`must find offsets when collapsed at end of nested node 1`] = `\nObject {\n  \"needsRecovery\": false,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 4,\n    \"focusKey\": \"b\",\n    \"focusOffset\": 4,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`must find offsets when collapsed at start 1`] = `\nObject {\n  \"needsRecovery\": false,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`must find offsets when collapsed at start of nested node 1`] = `\nObject {\n  \"needsRecovery\": false,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"b\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`occupies a single child of the contents 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 19,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`occupies a single child of the contents with nested blocks 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"b\",\n    \"focusOffset\": 4,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`reversed leaf to leaf 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"c\",\n    \"anchorOffset\": 7,\n    \"focusKey\": \"a\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": true,\n  },\n}\n`;\n\nexports[`reversed leaf to nested leaf 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"d\",\n    \"anchorOffset\": 5,\n    \"focusKey\": \"b\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": true,\n  },\n}\n`;\n\nexports[`starts at head of a nested text node, ends at head of leaf child of another nested node 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`starts at head of nested text node, ends at end of nested leaf child 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 5,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`starts at head of nested text node, ends at end of nested leaf span 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 5,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`starts at head of nested text node, ends at head of nested leaf span 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`starts at head of one nested node and ends at head of another nested node 1`] = `\nObject {\n  \"needsRecovery\": false,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`starts at head of one node and ends at head of another 1`] = `\nObject {\n  \"needsRecovery\": false,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`starts at head of text node, ends at end of leaf child 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 7,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`starts at head of text node, ends at end of leaf span 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 7,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`starts at head of text node, ends at head of leaf child 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`starts at head of text node, ends at head of leaf span 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 0,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`starts within nested text node, ends at end of nested leaf child 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 2,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 5,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`starts within nested text node, ends at end of nested leaf span 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 2,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 5,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`starts within nested text node, ends at start of nested leaf child 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 2,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`starts within nested text node, ends at start of nested leaf span 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 2,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`starts within one nested text node and ends within another nested block 1`] = `\nObject {\n  \"needsRecovery\": false,\n  \"selectionState\": Object {\n    \"anchorKey\": \"b\",\n    \"anchorOffset\": 2,\n    \"focusKey\": \"d\",\n    \"focusOffset\": 3,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`starts within one text node and ends within another block 1`] = `\nObject {\n  \"needsRecovery\": false,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 4,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 6,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`starts within text node, ends at end of leaf child 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 4,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 7,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`starts within text node, ends at end of leaf span 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 4,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 7,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`starts within text node, ends at start of leaf child 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 4,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n\nexports[`starts within text node, ends at start of leaf span 1`] = `\nObject {\n  \"needsRecovery\": true,\n  \"selectionState\": Object {\n    \"anchorKey\": \"a\",\n    \"anchorOffset\": 4,\n    \"focusKey\": \"c\",\n    \"focusOffset\": 0,\n    \"hasFocus\": false,\n    \"isBackward\": false,\n  },\n}\n`;\n"
  },
  {
    "path": "src/component/selection/__tests__/__snapshots__/setDraftEditorSelection-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`addFocusToSelection sets a new focus on the selection if selection.extend is unsupported 1`] = `\nSelection {\n  \"focusNode\": Washington,\n  \"focusOffset\": 0,\n  \"range\": Range {\n    \"endOffset\": 3,\n    \"node\": Washington,\n    \"startOffset\": 0,\n  },\n  \"rangeCount\": 1,\n}\n`;\n\nexports[`addFocusToSelection the range is not updated if rangeCount is 0 1`] = `\nSelection {\n  \"focusNode\": null,\n  \"focusOffset\": 0,\n  \"range\": null,\n  \"rangeCount\": 0,\n}\n`;\n"
  },
  {
    "path": "src/component/selection/__tests__/getDraftEditorSelection-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst getDraftEditorSelection = require('getDraftEditorSelection');\nconst getSampleSelectionMocksForTesting = require('getSampleSelectionMocksForTesting');\nconst getSampleSelectionMocksForTestingNestedBlocks = require('getSampleSelectionMocksForTestingNestedBlocks');\n\nlet editorState = null;\nlet root = null;\nlet contents = null;\nlet blocks = null;\nlet leafs = null;\nlet leafChildren = null;\nlet textNodes = null;\n\nconst resetRootNodeMocks = () => {\n  ({editorState, root, contents, blocks, leafs, leafChildren, textNodes} =\n    getSampleSelectionMocksForTesting());\n};\n\nconst resetNestedNodeMocks = () => {\n  ({editorState, root, contents, blocks, leafs, leafChildren, textNodes} =\n    getSampleSelectionMocksForTestingNestedBlocks());\n};\n\nconst assertGetDraftEditorSelection = getSelectionReturnValue => {\n  document.selection = null;\n  window.getSelection = jest.fn();\n  window.getSelection.mockReturnValueOnce(getSelectionReturnValue);\n  const selection = getDraftEditorSelection(editorState, root);\n  expect({\n    ...selection,\n    selectionState: selection.selectionState.toJS(),\n  }).toMatchSnapshot();\n};\n\nbeforeEach(() => {\n  resetRootNodeMocks();\n});\n\n/**\n * Test possible selection states for the text editor. This is based on\n * far too many hours of manual testing and bug fixes, and still may not be\n * a completely accurate representation of all subtle and bizarre differences\n * in implementations and APIs across browsers and operating systems.\n *\n * Welcome to the jungle.\n */\ntest('must find offsets when collapsed at start', () => {\n  const textNode = textNodes[0];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNode,\n    focusNode: textNode,\n    anchorOffset: 0,\n    focusOffset: 0,\n  });\n});\n\ntest('must find offsets when collapsed at start of nested node', () => {\n  resetNestedNodeMocks();\n  const textNode = textNodes[1];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNode,\n    focusNode: textNode,\n    anchorOffset: 0,\n    focusOffset: 0,\n  });\n});\n\ntest('must find offsets when collapsed at end', () => {\n  const textNode = textNodes[0];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNode,\n    focusNode: textNode,\n    anchorOffset: textNode.length,\n    focusOffset: textNode.length,\n  });\n});\n\ntest('must find offsets when collapsed at end of nested node', () => {\n  resetNestedNodeMocks();\n  const textNode = textNodes[1];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNode,\n    focusNode: textNode,\n    anchorOffset: textNode.length,\n    focusOffset: textNode.length,\n  });\n});\n\ntest('must find offsets for non-collapsed selection', () => {\n  const textNode = textNodes[0];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNode,\n    anchorOffset: 1,\n    focusNode: textNode,\n    focusOffset: 6,\n  });\n});\n\ntest('must find offsets for non-collapsed selection of nested node', () => {\n  resetNestedNodeMocks();\n  const textNode = textNodes[1];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNode,\n    anchorOffset: 1,\n    focusNode: textNode,\n    focusOffset: 2,\n  });\n});\n\ntest('must find offsets for reversed selection', () => {\n  const textNode = textNodes[0];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNode,\n    anchorOffset: 6,\n    focusNode: textNode,\n    focusOffset: 1,\n  });\n});\n\ntest('must find offsets for reversed selection of nested node', () => {\n  resetNestedNodeMocks();\n  const textNode = textNodes[1];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNode,\n    anchorOffset: 2,\n    focusNode: textNode,\n    focusOffset: 1,\n  });\n});\n\ntest('must find offsets for selection on entire text node', () => {\n  const textNode = textNodes[0];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNode,\n    anchorOffset: 0,\n    focusNode: textNode,\n    focusOffset: textNode.length,\n  });\n});\n\ntest('must find offsets for selection on entire text node of nested node', () => {\n  resetNestedNodeMocks();\n  const textNode = textNodes[1];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNode,\n    anchorOffset: 0,\n    focusNode: textNode,\n    focusOffset: textNode.length,\n  });\n});\n\ntest('starts at head of one node and ends at head of another', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[0],\n    anchorOffset: 0,\n    focusNode: textNodes[4],\n    focusOffset: 0,\n  });\n});\n\ntest('starts at head of one nested node and ends at head of another nested node', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[1],\n    anchorOffset: 0,\n    focusNode: textNodes[3],\n    focusOffset: 0,\n  });\n});\n\ntest('extends from head of one node to end of another', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[0],\n    anchorOffset: 0,\n    focusNode: textNodes[2],\n    focusOffset: textNodes[2].textContent.length,\n  });\n});\n\ntest('extends from head of one nested node to end of another nested node', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[1],\n    anchorOffset: 0,\n    focusNode: textNodes[3],\n    focusOffset: textNodes[3].textContent.length,\n  });\n});\n\ntest('starts within one text node and ends within another block', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[0],\n    anchorOffset: 4,\n    focusNode: textNodes[4],\n    focusOffset: 6,\n  });\n});\n\ntest('starts within one nested text node and ends within another nested block', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[1],\n    anchorOffset: 2,\n    focusNode: textNodes[3],\n    focusOffset: 3,\n  });\n});\n\ntest('is a reversed selection across multiple text nodes', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[4],\n    anchorOffset: 4,\n    focusNode: textNodes[0],\n    focusOffset: 6,\n  });\n});\n\ntest('is a reversed selection across multiple nested text nodes', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[1],\n    anchorOffset: 2,\n    focusNode: textNodes[3],\n    focusOffset: 3,\n  });\n});\n\n// I'm not even certain this is possible, but let's handle it anyway.\ntest('starts at head of text node, ends at head of leaf child', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[0],\n    anchorOffset: 0,\n    focusNode: leafChildren[4],\n    focusOffset: 0,\n  });\n});\n\ntest('starts at head of a nested text node, ends at head of leaf child of another nested node', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[1],\n    anchorOffset: 0,\n    focusNode: leafChildren[3],\n    focusOffset: 0,\n  });\n});\n\ntest('starts at head of text node, ends at end of leaf child', () => {\n  const leaf = leafChildren[4];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[0],\n    anchorOffset: 0,\n    focusNode: leaf,\n    focusOffset: leaf.childNodes.length,\n  });\n});\n\ntest('starts at head of nested text node, ends at end of nested leaf child', () => {\n  resetNestedNodeMocks();\n  const leaf = leafChildren[3];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[1],\n    anchorOffset: 0,\n    focusNode: leaf,\n    focusOffset: leaf.childNodes.length,\n  });\n});\n\ntest('starts within text node, ends at start of leaf child', () => {\n  const leaf = leafChildren[4];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[0],\n    anchorOffset: 4,\n    focusNode: leaf,\n    focusOffset: 0,\n  });\n});\n\ntest('starts within nested text node, ends at start of nested leaf child', () => {\n  resetNestedNodeMocks();\n  const leaf = leafChildren[3];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[1],\n    anchorOffset: 2,\n    focusNode: leaf,\n    focusOffset: 0,\n  });\n});\n\ntest('starts within text node, ends at end of leaf child', () => {\n  const leaf = leafChildren[4];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[0],\n    anchorOffset: 4,\n    focusNode: leaf,\n    focusOffset: leaf.childNodes.length,\n  });\n});\n\ntest('starts within nested text node, ends at end of nested leaf child', () => {\n  resetNestedNodeMocks();\n  const leaf = leafChildren[3];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[1],\n    anchorOffset: 2,\n    focusNode: leaf,\n    focusOffset: leaf.childNodes.length,\n  });\n});\n\ntest('is a reversed text-to-leaf-child selection', () => {\n  const leaf = leafChildren[4];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: leaf,\n    anchorOffset: 0,\n    focusNode: textNodes[0],\n    focusOffset: 4,\n  });\n});\n\ntest('is a reversed text-to-leaf-child selection of nested node', () => {\n  resetNestedNodeMocks();\n  const leaf = leafChildren[3];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: leaf,\n    anchorOffset: 0,\n    focusNode: textNodes[1],\n    focusOffset: 4,\n  });\n});\n\ntest('starts at head of text node, ends at head of leaf span', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[0],\n    anchorOffset: 0,\n    focusNode: leafs[4],\n    focusOffset: 0,\n  });\n});\n\ntest('starts at head of nested text node, ends at head of nested leaf span', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[1],\n    anchorOffset: 0,\n    focusNode: leafs[3],\n    focusOffset: 0,\n  });\n});\n\ntest('starts at head of text node, ends at end of leaf span', () => {\n  const leaf = leafs[4];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[0],\n    anchorOffset: 0,\n    focusNode: leaf,\n    focusOffset: leaf.childNodes.length,\n  });\n});\n\ntest('starts at head of nested text node, ends at end of nested leaf span', () => {\n  resetNestedNodeMocks();\n  const leaf = leafs[3];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[1],\n    anchorOffset: 0,\n    focusNode: leaf,\n    focusOffset: leaf.childNodes.length,\n  });\n});\n\ntest('starts within text node, ends at start of leaf span', () => {\n  const leaf = leafs[4];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[0],\n    anchorOffset: 4,\n    focusNode: leaf,\n    focusOffset: 0,\n  });\n});\n\ntest('starts within nested text node, ends at start of nested leaf span', () => {\n  resetNestedNodeMocks();\n  const leaf = leafs[3];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[1],\n    anchorOffset: 2,\n    focusNode: leaf,\n    focusOffset: 0,\n  });\n});\n\ntest('starts within text node, ends at end of leaf span', () => {\n  const leaf = leafs[4];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[0],\n    anchorOffset: 4,\n    focusNode: leaf,\n    focusOffset: leaf.childNodes.length,\n  });\n});\n\ntest('starts within nested text node, ends at end of nested leaf span', () => {\n  resetNestedNodeMocks();\n  const leaf = leafs[3];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[1],\n    anchorOffset: 2,\n    focusNode: leaf,\n    focusOffset: leaf.childNodes.length,\n  });\n});\n\ntest('is a reversed text-to-leaf selection', () => {\n  const leaf = leafs[4];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: leaf,\n    anchorOffset: 0,\n    focusNode: textNodes[0],\n    focusOffset: 4,\n  });\n});\n\ntest('is a reversed nested text-to-leaf selection', () => {\n  resetNestedNodeMocks();\n  const leaf = leafs[3];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: leaf,\n    anchorOffset: 0,\n    focusNode: textNodes[1],\n    focusOffset: 2,\n  });\n});\n\ntest('is collapsed at start of single span', () => {\n  const leaf = leafs[0];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: leaf,\n    anchorOffset: 0,\n    focusNode: leaf,\n    focusOffset: 0,\n  });\n});\n\ntest('is collapsed at start of nested single span', () => {\n  resetNestedNodeMocks();\n  const leaf = leafs[1];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: leaf,\n    anchorOffset: 0,\n    focusNode: leaf,\n    focusOffset: 0,\n  });\n});\n\ntest('is collapsed at end of single span', () => {\n  const leaf = leafs[0];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: leaf,\n    anchorOffset: leaf.childNodes.length,\n    focusNode: leaf,\n    focusOffset: leaf.childNodes.length,\n  });\n});\n\ntest('is collapsed at end of nested single span', () => {\n  resetNestedNodeMocks();\n  const leaf = leafs[1];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: leaf,\n    anchorOffset: leaf.childNodes.length,\n    focusNode: leaf,\n    focusOffset: leaf.childNodes.length,\n  });\n});\n\ntest('contains an entire leaf', () => {\n  const leaf = leafs[4];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: leaf,\n    anchorOffset: 0,\n    focusNode: leaf,\n    focusOffset: leaf.childNodes.length,\n  });\n});\n\ntest('contains an entire nested leaf', () => {\n  resetNestedNodeMocks();\n  const leaf = leafs[3];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: leaf,\n    anchorOffset: 0,\n    focusNode: leaf,\n    focusOffset: leaf.childNodes.length,\n  });\n});\n\ntest('is reversed on entire leaf', () => {\n  const leaf = leafs[4];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: leaf,\n    anchorOffset: leaf.childNodes.length,\n    focusNode: leaf,\n    focusOffset: 0,\n  });\n});\n\ntest('is reversed on nested entire leaf', () => {\n  resetNestedNodeMocks();\n  const leaf = leafs[3];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: leaf,\n    anchorOffset: leaf.childNodes.length,\n    focusNode: leaf,\n    focusOffset: 0,\n  });\n});\n\ntest('from start of one block to start of another', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: leafs[0],\n    anchorOffset: 0,\n    focusNode: leafs[4],\n    focusOffset: 0,\n  });\n});\n\ntest('from start of one nested block to start of another', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: leafs[1],\n    anchorOffset: 0,\n    focusNode: leafs[3],\n    focusOffset: 0,\n  });\n});\n\ntest('from start of one block to end of other block', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: leafs[0],\n    anchorOffset: 0,\n    focusNode: leafs[4],\n    focusOffset: leafs[4].childNodes.length,\n  });\n});\n\ntest('from start of one nestd block to end of other nested block', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: leafs[1],\n    anchorOffset: 0,\n    focusNode: leafs[3],\n    focusOffset: leafs[3].childNodes.length,\n  });\n});\n\ntest('reversed leaf to leaf', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: leafs[4],\n    anchorOffset: leafs[4].childNodes.length,\n    focusNode: leafs[0],\n    focusOffset: 0,\n  });\n});\n\ntest('reversed leaf to nested leaf', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: leafs[3],\n    anchorOffset: leafs[3].childNodes.length,\n    focusNode: leafs[1],\n    focusOffset: 0,\n  });\n});\n\ntest('is collapsed at start at single block', () => {\n  const block = blocks[0];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: block,\n    anchorOffset: 0,\n    focusNode: block,\n    focusOffset: 0,\n  });\n});\n\ntest('is collapsed at start at nested single block', () => {\n  resetNestedNodeMocks();\n  const block = blocks[1];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: block,\n    anchorOffset: 0,\n    focusNode: block,\n    focusOffset: 0,\n  });\n});\n\ntest('is collapsed at end at single block', () => {\n  const block = blocks[0];\n  const decorators = block.childNodes;\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: block,\n    anchorOffset: decorators.length,\n    focusNode: block,\n    focusOffset: decorators.length,\n  });\n});\n\ntest('is collapsed at end at nested single block', () => {\n  resetNestedNodeMocks();\n  const block = blocks[1];\n  const decorators = block.childNodes;\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: block,\n    anchorOffset: decorators.length,\n    focusNode: block,\n    focusOffset: decorators.length,\n  });\n});\n\ntest('is entirely selected', () => {\n  const block = blocks[0];\n  const decorators = block.childNodes;\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: block,\n    anchorOffset: 0,\n    focusNode: block,\n    focusOffset: decorators.length,\n  });\n});\n\ntest('is entirely selected with nested blocks', () => {\n  resetNestedNodeMocks();\n  const block = blocks[1];\n  const decorators = block.childNodes;\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: block,\n    anchorOffset: 0,\n    focusNode: block,\n    focusOffset: decorators.length,\n  });\n});\n\n/**\n * FF: Triple-clicking a block leads to an entire block being selected,\n * with the first text node as the anchor (0 offset) and the block element\n * as the focus (childNodes.length offset)\n */\ntest('begins at text node zero, ends at end of block', () => {\n  const textNode = textNodes[0];\n  const block = blocks[0];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNode,\n    anchorOffset: 0,\n    focusNode: block,\n    focusOffset: block.childNodes.length,\n  });\n});\n\ntest('begins at nested text node zero, ends at end of nested block', () => {\n  resetNestedNodeMocks();\n  const textNode = textNodes[1];\n  const block = blocks[1];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNode,\n    anchorOffset: 0,\n    focusNode: block,\n    focusOffset: block.childNodes.length,\n  });\n});\n\n// No idea if this is possible.\ntest('begins within text node, ends at end of block', () => {\n  const textNode = textNodes[0];\n  const block = blocks[0];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNode,\n    anchorOffset: 5,\n    focusNode: block,\n    focusOffset: block.childNodes.length,\n  });\n});\n\ntest('begins within nested text node, ends at end of nested block', () => {\n  resetNestedNodeMocks();\n  const textNode = textNodes[1];\n  const block = blocks[1];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNode,\n    anchorOffset: 2,\n    focusNode: block,\n    focusOffset: block.childNodes.length,\n  });\n});\n\n// No idea if this is possible.\ntest('is reversed from the first case', () => {\n  const textNode = textNodes[0];\n  const block = blocks[0];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: block,\n    anchorOffset: block.childNodes.length,\n    focusNode: textNode,\n    focusOffset: 0,\n  });\n});\n\ntest('is reversed from the first nested case', () => {\n  resetNestedNodeMocks();\n  const textNode = textNodes[1];\n  const block = blocks[1];\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: block,\n    anchorOffset: block.childNodes.length,\n    focusNode: textNode,\n    focusOffset: 0,\n  });\n});\n\ntest('goes from start of one block to end of other block', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: blocks[0],\n    anchorOffset: 0,\n    focusNode: blocks[2],\n    focusOffset: blocks[2].childNodes.length,\n  });\n});\n\ntest('goes from start of one nested block to end of other nested block', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: blocks[1],\n    anchorOffset: 0,\n    focusNode: blocks[3],\n    focusOffset: blocks[3].childNodes.length,\n  });\n});\n\ntest('goes from start of one block to start of other', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: blocks[0],\n    anchorOffset: 0,\n    focusNode: blocks[2],\n    focusOffset: 0,\n  });\n});\n\ntest('goes from start of one nested block to start of other', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: blocks[1],\n    anchorOffset: 0,\n    focusNode: blocks[3],\n    focusOffset: 0,\n  });\n});\n\ntest('goes from end of one to end of other block', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: blocks[0],\n    anchorOffset: blocks[0].childNodes.length,\n    focusNode: blocks[2],\n    focusOffset: blocks[2].childNodes.length,\n  });\n});\n\ntest('goes from end of one nested block to end of other nested block', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: blocks[1],\n    anchorOffset: blocks[1].childNodes.length,\n    focusNode: blocks[3],\n    focusOffset: blocks[3].childNodes.length,\n  });\n});\n\ntest('goes from within one block to within another block', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: blocks[0],\n    anchorOffset: 1,\n    focusNode: blocks[2].firstChild.firstChild,\n    focusOffset: 1,\n  });\n});\n\ntest('goes from within one nested block to within another nested block', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: blocks[1],\n    anchorOffset: 1,\n    focusNode: blocks[3].firstChild.firstChild,\n    focusOffset: 1,\n  });\n});\n\ntest('is the same as above but reversed', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: blocks[2].firstChild.firstChild,\n    anchorOffset: 1,\n    focusNode: blocks[0],\n    focusOffset: 1,\n  });\n});\n\ntest('is the same as above but nested and reversed', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: blocks[3].firstChild.firstChild,\n    anchorOffset: 1,\n    focusNode: blocks[1],\n    focusOffset: 1,\n  });\n});\n\ntest('is collapsed at the start of the contents', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: contents,\n    anchorOffset: 0,\n    focusNode: contents,\n    focusOffset: 0,\n  });\n});\n\ntest('is collapsed at the start of the contents with nesting blocks', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: contents,\n    anchorOffset: 0,\n    focusNode: contents,\n    focusOffset: 0,\n  });\n});\n\ntest('occupies a single child of the contents', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: contents,\n    anchorOffset: 0,\n    focusNode: contents,\n    focusOffset: 1,\n  });\n});\n\ntest('occupies a single child of the contents with nested blocks', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: contents,\n    anchorOffset: 0,\n    focusNode: contents,\n    focusOffset: 1,\n  });\n});\n\ntest('is collapsed at the end of a child', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: contents,\n    anchorOffset: 1,\n    focusNode: contents,\n    focusOffset: 1,\n  });\n});\n\ntest('is collapsed at the end of a nested child', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: contents,\n    anchorOffset: 1,\n    focusNode: contents,\n    focusOffset: 1,\n  });\n});\n\ntest('is contains multiple children', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: contents,\n    anchorOffset: 0,\n    focusNode: contents,\n    focusOffset: 3,\n  });\n});\n\ntest('is contains multiple nested children', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: contents,\n    anchorOffset: 0,\n    focusNode: contents,\n    focusOffset: 2,\n  });\n});\n\n/**\n * In some scenarios, the entire editor may be selected by command-A.\n */\ntest('is collapsed at start with full selection', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: root,\n    anchorOffset: 0,\n    focusNode: root,\n    focusOffset: 0,\n  });\n});\n\ntest('is collapsed at start with full selection with nested blocks', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: root,\n    anchorOffset: 0,\n    focusNode: root,\n    focusOffset: 0,\n  });\n});\n\ntest('is collapsed at end with full selection', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: root,\n    anchorOffset: root.childNodes.length,\n    focusNode: root,\n    focusOffset: root.childNodes.length,\n  });\n});\n\ntest('is collapsed at end with full selection with nested blocks', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: root,\n    anchorOffset: root.childNodes.length,\n    focusNode: root,\n    focusOffset: root.childNodes.length,\n  });\n});\n\ntest('is completely selected', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: root,\n    anchorOffset: 0,\n    focusNode: root,\n    focusOffset: root.childNodes.length,\n  });\n});\n\ntest('is completely selected with nested blocks', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: root,\n    anchorOffset: 0,\n    focusNode: root,\n    focusOffset: root.childNodes.length,\n  });\n});\n\ntest('is reversed from above', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: root,\n    anchorOffset: root.childNodes.length,\n    focusNode: root,\n    focusOffset: 0,\n  });\n});\n\ntest('is reversed from above nested blocks', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: root,\n    anchorOffset: root.childNodes.length,\n    focusNode: root,\n    focusOffset: 0,\n  });\n});\n\n/**\n * A selection possibility that defies logic. In IE11, triple clicking a\n * block leads to the text node being selected as the anchor, and the\n * **entire editor** being selected as the focus. Ludicrous.\n */\ntest('does the crazy stuff described above', () => {\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[0],\n    anchorOffset: 0,\n    focusNode: root,\n    focusOffset: root.childNodes.length,\n  });\n});\n\ntest('does the crazy stuff described above with nested blocks', () => {\n  resetNestedNodeMocks();\n  assertGetDraftEditorSelection({\n    rangeCount: 1,\n    anchorNode: textNodes[1],\n    anchorOffset: 0,\n    focusNode: root,\n    focusOffset: root.childNodes.length,\n  });\n});\n"
  },
  {
    "path": "src/component/selection/__tests__/setDraftEditorSelection-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\njest.disableAutomock();\n\nconst getSampleSelectionMocksForTesting = require('getSampleSelectionMocksForTesting');\nconst addFocusToSelection =\n  require('setDraftEditorSelection').addFocusToSelection;\n\n// Based on https://w3c.github.io/selection-api/#selection-interface\nclass Selection {\n  constructor({range}) {\n    this.rangeCount = range ? 1 : 0;\n    this.focusNode = (range && range.node) || null;\n    this.focusOffset = (range && range.startOffset) || 0;\n    this.range = range || null;\n  }\n\n  getRangeAt(idx) {\n    if (idx !== 0 || this.rangeCount <= 0) {\n      throw new Error('IndexSizeError');\n    }\n    return this.range;\n  }\n\n  addRange(range) {\n    this.range = range;\n    this.rangeCount = 1;\n  }\n}\n\n// Based on https://dom.spec.whatwg.org/#concept-range\nclass Range {\n  constructor({startOffset, endOffset, node}) {\n    this.startOffset = startOffset;\n    this.endOffset = endOffset;\n    this.node = node;\n  }\n\n  setEnd(node, offset) {\n    this.endOffset = offset;\n    this.node = node;\n  }\n\n  cloneRange() {\n    return new Range({\n      startOffset: this.startOffset,\n      endOffset: this.endOffset,\n      node: this.node,\n    });\n  }\n}\n\nlet editorState = null;\nlet textNodes = null;\n\nconst resetRootNodeMocks = () => {\n  ({editorState, textNodes} = getSampleSelectionMocksForTesting());\n};\n\nbeforeEach(() => {\n  resetRootNodeMocks();\n});\n\ndescribe('addFocusToSelection', () => {\n  test('sets a new focus on the selection if selection.extend is unsupported', () => {\n    const range = new Range({\n      startOffset: 0,\n      endOffset: 0,\n      node: textNodes[0],\n    });\n    const selection = new Selection({range});\n    const storedFocusNode = selection.focusNode;\n    const storedFocusOffset = 3;\n    addFocusToSelection(\n      selection,\n      storedFocusNode,\n      storedFocusOffset,\n      editorState.getSelection(),\n    );\n    expect(selection).toMatchSnapshot();\n  });\n\n  // If rangeCount is 0, selection.getRangeAt() will throw on various browsers\n  test('the range is not updated if rangeCount is 0', () => {\n    const selection = new Selection({});\n    const storedFocusNode = selection.focusNode;\n    const storedFocusOffset = 3;\n    addFocusToSelection(\n      selection,\n      storedFocusNode,\n      storedFocusOffset,\n      editorState.getSelection(),\n    );\n    expect(selection).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "src/component/selection/expandRangeToStartOfLine.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\nconst UnicodeUtils = require('UnicodeUtils');\n\nconst getCorrectDocumentFromNode = require('getCorrectDocumentFromNode');\nconst getRangeClientRects = require('getRangeClientRects');\nconst invariant = require('invariant');\n/**\n * Return the computed line height, in pixels, for the provided element.\n */\nfunction getLineHeightPx(element: Element): number {\n  const computed = getComputedStyle(element);\n  const correctDocument = getCorrectDocumentFromNode(element);\n  const div = correctDocument.createElement('div');\n  div.style.fontFamily = computed.fontFamily;\n  div.style.fontSize = computed.fontSize;\n  div.style.fontStyle = computed.fontStyle;\n  div.style.fontWeight = computed.fontWeight;\n  div.style.lineHeight = computed.lineHeight;\n  div.style.position = 'absolute';\n  div.textContent = 'M';\n\n  const documentBody = correctDocument.body;\n  invariant(documentBody, 'Missing document.body');\n\n  // forced layout here\n  documentBody.appendChild(div);\n  const rect = div.getBoundingClientRect();\n  documentBody.removeChild(div);\n\n  return rect.height;\n}\n\n/**\n * Return whether every ClientRect in the provided list lies on the same line.\n *\n * We assume that the rects on the same line all contain the baseline, so the\n * lowest top line needs to be above the highest bottom line (i.e., if you were\n * to project the rects onto the y-axis, their intersection would be nonempty).\n *\n * In addition, we require that no two boxes are lineHeight (or more) apart at\n * either top or bottom, which helps protect against false positives for fonts\n * with extremely large glyph heights (e.g., with a font size of 17px, Zapfino\n * produces rects of height 58px!).\n */\nfunction areRectsOnOneLine(\n  rects: Array<ClientRect>,\n  lineHeight: number,\n): boolean {\n  let minTop = Infinity;\n  let minBottom = Infinity;\n  let maxTop = -Infinity;\n  let maxBottom = -Infinity;\n\n  for (let ii = 0; ii < rects.length; ii++) {\n    const rect = rects[ii];\n    if (rect.width === 0 || rect.width === 1) {\n      // When a range starts or ends a soft wrap, many browsers (Chrome, IE,\n      // Safari) include an empty rect on the previous or next line. When the\n      // text lies in a container whose position is not integral (e.g., from\n      // margin: auto), Safari makes these empty rects have width 1 (instead of\n      // 0). Having one-pixel-wide characters seems unlikely (and most browsers\n      // report widths in subpixel precision anyway) so it's relatively safe to\n      // skip over them.\n      continue;\n    }\n    minTop = Math.min(minTop, rect.top);\n    minBottom = Math.min(minBottom, rect.bottom);\n    maxTop = Math.max(maxTop, rect.top);\n    maxBottom = Math.max(maxBottom, rect.bottom);\n  }\n\n  return (\n    maxTop <= minBottom &&\n    maxTop - minTop < lineHeight &&\n    maxBottom - minBottom < lineHeight\n  );\n}\n\n/**\n * Return the length of a node, as used by Range offsets.\n */\nfunction getNodeLength(node: Node): number {\n  // http://www.w3.org/TR/dom/#concept-node-length\n  switch (node.nodeType) {\n    case Node.DOCUMENT_TYPE_NODE:\n      return 0;\n    case Node.TEXT_NODE:\n    case Node.PROCESSING_INSTRUCTION_NODE:\n    case Node.COMMENT_NODE:\n      return (node: any).length;\n    default:\n      return node.childNodes.length;\n  }\n}\n\n/**\n * Given a collapsed range, move the start position backwards as far as\n * possible while the range still spans only a single line.\n */\nfunction expandRangeToStartOfLine(range: Range): Range {\n  invariant(\n    range.collapsed,\n    'expandRangeToStartOfLine: Provided range is not collapsed.',\n  );\n  range = range.cloneRange();\n\n  let containingElement: ?Node = range.startContainer;\n  // $FlowFixMe[incompatible-type]\n  // $FlowFixMe[incompatible-use]\n  if (containingElement.nodeType !== 1) {\n    // $FlowFixMe[incompatible-use]\n    containingElement = containingElement.parentNode;\n  }\n  const lineHeight = getLineHeightPx((containingElement: any));\n\n  // Imagine our text looks like:\n  //   <div><span>once upon a time, there was a <em>boy\n  //   who lived</em> </span><q><strong>under^ the\n  //   stairs</strong> in a small closet.</q></div>\n  // where the caret represents the cursor. First, we crawl up the tree until\n  // the range spans multiple lines (setting the start point to before\n  // \"<strong>\", then before \"<div>\"), then at each level we do a search to\n  // find the latest point which is still on a previous line. We'll find that\n  // the break point is inside the span, then inside the <em>, then in its text\n  // node child, the actual break point before \"who\".\n\n  let bestContainer = range.endContainer;\n  let bestOffset = range.endOffset;\n  range.setStart(range.startContainer, 0);\n\n  while (areRectsOnOneLine(getRangeClientRects(range), lineHeight)) {\n    bestContainer = range.startContainer;\n    bestOffset = range.startOffset;\n    invariant(\n      bestContainer.parentNode,\n      'Found unexpected detached subtree when traversing.',\n    );\n    range.setStartBefore(bestContainer);\n    if (\n      bestContainer.nodeType === 1 &&\n      getComputedStyle((bestContainer: any)).display !== 'inline'\n    ) {\n      // The start of the line is never in a different block-level container.\n      break;\n    }\n  }\n\n  // In the above example, range now spans from \"<div>\" to \"under\",\n  // bestContainer is <div>, and bestOffset is 1 (index of <q> inside <div>)].\n  // Picking out which child to recurse into here is a special case since we\n  // don't want to check past <q> -- once we find that the final range starts\n  // in <span>, we can look at all of its children (and all of their children)\n  // to find the break point.\n\n  // At all times, (bestContainer, bestOffset) is the latest single-line start\n  // point that we know of.\n  let currentContainer = bestContainer;\n  let maxIndexToConsider = bestOffset - 1;\n\n  do {\n    const nodeValue = currentContainer.nodeValue;\n    let ii = maxIndexToConsider;\n\n    for (; ii >= 0; ii--) {\n      if (\n        nodeValue != null &&\n        ii > 0 &&\n        UnicodeUtils.isSurrogatePair(nodeValue, ii - 1)\n      ) {\n        // We're in the middle of a surrogate pair -- skip over so we never\n        // return a range with an endpoint in the middle of a code point.\n        continue;\n      }\n\n      range.setStart(currentContainer, ii);\n      if (areRectsOnOneLine(getRangeClientRects(range), lineHeight)) {\n        bestContainer = currentContainer;\n        bestOffset = ii;\n      } else {\n        break;\n      }\n    }\n\n    if (ii === -1 || currentContainer.childNodes.length === 0) {\n      // If ii === -1, then (bestContainer, bestOffset), which is equal to\n      // (currentContainer, 0), was a single-line start point but a start\n      // point before currentContainer wasn't, so the line break seems to\n      // have occurred immediately after currentContainer's start tag\n      //\n      // If currentContainer.childNodes.length === 0, we're already at a\n      // terminal node (e.g., text node) and should return our current best.\n      break;\n    }\n\n    currentContainer = currentContainer.childNodes[ii];\n    maxIndexToConsider = getNodeLength(currentContainer);\n  } while (true);\n\n  range.setStart(bestContainer, bestOffset);\n  return range;\n}\n\nmodule.exports = expandRangeToStartOfLine;\n"
  },
  {
    "path": "src/component/selection/findAncestorOffsetKey.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst getCorrectDocumentFromNode = require('getCorrectDocumentFromNode');\nconst getSelectionOffsetKeyForNode = require('getSelectionOffsetKeyForNode');\n/**\n * Get the key from the node's nearest offset-aware ancestor.\n */\nfunction findAncestorOffsetKey(node: Node): ?string {\n  let searchNode: ?Node = node;\n  while (\n    searchNode &&\n    searchNode !== getCorrectDocumentFromNode(node).documentElement\n  ) {\n    const key = getSelectionOffsetKeyForNode(searchNode);\n    if (key != null) {\n      return key;\n    }\n    searchNode = searchNode.parentNode;\n  }\n  return null;\n}\n\nmodule.exports = findAncestorOffsetKey;\n"
  },
  {
    "path": "src/component/selection/getDraftEditorSelection.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {DOMDerivedSelection} from 'DOMDerivedSelection';\nimport type {SelectionObject} from 'DraftDOMTypes';\nimport type EditorState from 'EditorState';\n\nconst getDraftEditorSelectionWithNodes = require('getDraftEditorSelectionWithNodes');\n\n/**\n * Convert the current selection range to an anchor/focus pair of offset keys\n * and values that can be interpreted by components.\n */\nfunction getDraftEditorSelection(\n  editorState: EditorState,\n  root: HTMLElement,\n): DOMDerivedSelection {\n  const selection: SelectionObject =\n    root.ownerDocument.defaultView.getSelection();\n  const {anchorNode, anchorOffset, focusNode, focusOffset, rangeCount} =\n    selection;\n\n  if (\n    // No active selection.\n    rangeCount === 0 ||\n    // No selection, ever. As in, the user hasn't selected anything since\n    // opening the document.\n    anchorNode == null ||\n    focusNode == null\n  ) {\n    return {\n      selectionState: editorState.getSelection().set('hasFocus', false),\n      needsRecovery: false,\n    };\n  }\n\n  return getDraftEditorSelectionWithNodes(\n    editorState,\n    root,\n    anchorNode,\n    anchorOffset,\n    focusNode,\n    focusOffset,\n  );\n}\n\nmodule.exports = getDraftEditorSelection;\n"
  },
  {
    "path": "src/component/selection/getDraftEditorSelectionWithNodes.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {DOMDerivedSelection} from 'DOMDerivedSelection';\nimport type EditorState from 'EditorState';\n\nconst findAncestorOffsetKey = require('findAncestorOffsetKey');\nconst getSelectionOffsetKeyForNode = require('getSelectionOffsetKeyForNode');\nconst getUpdatedSelectionState = require('getUpdatedSelectionState');\nconst invariant = require('invariant');\nconst isElement = require('isElement');\nconst nullthrows = require('nullthrows');\n\ntype SelectionPoint = {\n  key: string,\n  offset: number,\n};\n\n/**\n * Convert the current selection range to an anchor/focus pair of offset keys\n * and values that can be interpreted by components.\n */\nfunction getDraftEditorSelectionWithNodes(\n  editorState: EditorState,\n  root: ?HTMLElement,\n  anchorNode: Node,\n  anchorOffset: number,\n  focusNode: Node,\n  focusOffset: number,\n): DOMDerivedSelection {\n  const anchorIsTextNode = anchorNode.nodeType === Node.TEXT_NODE;\n  const focusIsTextNode = focusNode.nodeType === Node.TEXT_NODE;\n\n  // If the selection range lies only on text nodes, the task is simple.\n  // Find the nearest offset-aware elements and use the\n  // offset values supplied by the selection range.\n  if (anchorIsTextNode && focusIsTextNode) {\n    return {\n      selectionState: getUpdatedSelectionState(\n        editorState,\n        nullthrows(findAncestorOffsetKey(anchorNode)),\n        anchorOffset,\n        nullthrows(findAncestorOffsetKey(focusNode)),\n        focusOffset,\n      ),\n      needsRecovery: false,\n    };\n  }\n\n  let anchorPoint = null;\n  let focusPoint = null;\n  let needsRecovery = true;\n\n  // An element is selected. Convert this selection range into leaf offset\n  // keys and offset values for consumption at the component level. This\n  // is common in Firefox, where select-all and triple click behavior leads\n  // to entire elements being selected.\n  //\n  // Note that we use the `needsRecovery` parameter in the callback here. This\n  // is because when certain elements are selected, the behavior for subsequent\n  // cursor movement (e.g. via arrow keys) is uncertain and may not match\n  // expectations at the component level. For example, if an entire <div> is\n  // selected and the user presses the right arrow, Firefox keeps the selection\n  // on the <div>. If we allow subsequent keypresses to insert characters\n  // natively, they will be inserted into a browser-created text node to the\n  // right of that <div>. This is obviously undesirable.\n  //\n  // With the `needsRecovery` flag, we inform the caller that it is responsible\n  // for manually setting the selection state on the rendered document to\n  // ensure proper selection state maintenance.\n\n  if (anchorIsTextNode) {\n    anchorPoint = {\n      key: nullthrows(findAncestorOffsetKey(anchorNode)),\n      offset: anchorOffset,\n    };\n    focusPoint = getPointForNonTextNode(root, focusNode, focusOffset);\n  } else if (focusIsTextNode) {\n    focusPoint = {\n      key: nullthrows(findAncestorOffsetKey(focusNode)),\n      offset: focusOffset,\n    };\n    anchorPoint = getPointForNonTextNode(root, anchorNode, anchorOffset);\n  } else {\n    anchorPoint = getPointForNonTextNode(root, anchorNode, anchorOffset);\n    focusPoint = getPointForNonTextNode(root, focusNode, focusOffset);\n\n    // If the selection is collapsed on an empty block, don't force recovery.\n    // This way, on arrow key selection changes, the browser can move the\n    // cursor from a non-zero offset on one block, through empty blocks,\n    // to a matching non-zero offset on other text blocks.\n    if (anchorNode === focusNode && anchorOffset === focusOffset) {\n      needsRecovery =\n        !!anchorNode.firstChild && anchorNode.firstChild.nodeName !== 'BR';\n    }\n  }\n\n  return {\n    selectionState: getUpdatedSelectionState(\n      editorState,\n      anchorPoint.key,\n      anchorPoint.offset,\n      focusPoint.key,\n      focusPoint.offset,\n    ),\n    needsRecovery,\n  };\n}\n\n/**\n * Identify the first leaf descendant for the given node.\n */\nfunction getFirstLeaf(node: any): Node {\n  while (\n    node.firstChild &&\n    // data-blocks has no offset\n    ((isElement(node.firstChild) &&\n      (node.firstChild: Element).getAttribute('data-blocks') === 'true') ||\n      getSelectionOffsetKeyForNode(node.firstChild))\n  ) {\n    node = node.firstChild;\n  }\n  return node;\n}\n\n/**\n * Identify the last leaf descendant for the given node.\n */\nfunction getLastLeaf(node: any): Node {\n  while (\n    node.lastChild &&\n    // data-blocks has no offset\n    ((isElement(node.lastChild) &&\n      node.lastChild.getAttribute('data-blocks') === 'true') ||\n      getSelectionOffsetKeyForNode(node.lastChild))\n  ) {\n    node = node.lastChild;\n  }\n  return node;\n}\n\nfunction getPointForNonTextNode(\n  editorRoot: ?HTMLElement,\n  startNode: Node,\n  childOffset: number,\n): SelectionPoint {\n  let node: ?(Node | Element) = startNode;\n  // $FlowFixMe[incompatible-call]\n  const offsetKey: ?string = findAncestorOffsetKey(node);\n\n  invariant(\n    offsetKey != null ||\n      (editorRoot && (editorRoot === node || editorRoot.firstChild === node)),\n    'Unknown node in selection range.',\n  );\n\n  // If the editorRoot is the selection, step downward into the content\n  // wrapper.\n  if (editorRoot === node) {\n    // $FlowFixMe[incompatible-use]\n    node = node.firstChild;\n    invariant(\n      isElement(node),\n      'Invalid DraftEditorContents node. Expected element but instead got a node with type of %s.',\n      [node?.nodeType],\n    );\n    const castedNode: Element = (node: any);\n\n    // assignment only added for flow :/\n    // otherwise it throws in line 200 saying that node can be null or undefined\n    node = castedNode;\n    invariant(\n      node.getAttribute('data-contents') === 'true',\n      'Invalid DraftEditorContents structure.',\n    );\n    if (childOffset > 0) {\n      childOffset = node.childNodes.length;\n    }\n  }\n\n  // If the child offset is zero and we have an offset key, we're done.\n  // If there's no offset key because the entire editor is selected,\n  // find the leftmost (\"first\") leaf in the tree and use that as the offset\n  // key.\n  if (childOffset === 0) {\n    let key: ?string = null;\n    if (offsetKey != null) {\n      key = offsetKey;\n    } else {\n      const firstLeaf = getFirstLeaf(node);\n      key = nullthrows(getSelectionOffsetKeyForNode(firstLeaf));\n    }\n    return {key, offset: 0};\n  }\n\n  // $FlowFixMe[incompatible-use]\n  const nodeBeforeCursor = node.childNodes[childOffset - 1];\n  let leafKey: ?string = null;\n  let textLength: ?number = null;\n\n  if (!getSelectionOffsetKeyForNode(nodeBeforeCursor)) {\n    // Our target node may be a leaf or a text node, in which case we're\n    // already where we want to be and can just use the child's length as\n    // our offset.\n    leafKey = nullthrows(offsetKey);\n    textLength = getTextContentLength(nodeBeforeCursor);\n  } else {\n    // Otherwise, we'll look at the child to the left of the cursor and find\n    // the last leaf node in its subtree.\n    const lastLeaf = getLastLeaf(nodeBeforeCursor);\n    leafKey = nullthrows(getSelectionOffsetKeyForNode(lastLeaf));\n    textLength = getTextContentLength(lastLeaf);\n  }\n\n  return {\n    key: leafKey,\n    offset: textLength,\n  };\n}\n\n/**\n * Return the length of a node's textContent, regarding single newline\n * characters as zero-length. This allows us to avoid problems with identifying\n * the correct selection offset for empty blocks in IE, in which we\n * render newlines instead of break tags.\n */\nfunction getTextContentLength(node: Node): number {\n  const textContent = node.textContent;\n  return textContent === '\\n' ? 0 : textContent.length;\n}\n\nmodule.exports = getDraftEditorSelectionWithNodes;\n"
  },
  {
    "path": "src/component/selection/getRangeBoundingClientRect.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst getRangeClientRects = require('getRangeClientRects');\n\nexport type FakeClientRect = {\n  left: number,\n  width: number,\n  right: number,\n  top: number,\n  bottom: number,\n  height: number,\n};\n\n/**\n * Like range.getBoundingClientRect() but normalizes for browser bugs.\n */\nfunction getRangeBoundingClientRect(range: Range): FakeClientRect {\n  // \"Return a DOMRect object describing the smallest rectangle that includes\n  // the first rectangle in list and all of the remaining rectangles of which\n  // the height or width is not zero.\"\n  // http://www.w3.org/TR/cssom-view/#dom-range-getboundingclientrect\n  const rects = getRangeClientRects(range);\n  let top = 0;\n  let right = 0;\n  let bottom = 0;\n  let left = 0;\n\n  if (rects.length) {\n    // If the first rectangle has 0 width, we use the second, this is needed\n    // because Chrome renders a 0 width rectangle when the selection contains\n    // a line break.\n    if (rects.length > 1 && rects[0].width === 0) {\n      ({top, right, bottom, left} = rects[1]);\n    } else {\n      ({top, right, bottom, left} = rects[0]);\n    }\n\n    for (let ii = 1; ii < rects.length; ii++) {\n      const rect = rects[ii];\n      if (rect.height !== 0 && rect.width !== 0) {\n        top = Math.min(top, rect.top);\n        right = Math.max(right, rect.right);\n        bottom = Math.max(bottom, rect.bottom);\n        left = Math.min(left, rect.left);\n      }\n    }\n  }\n\n  return {\n    top,\n    right,\n    bottom,\n    left,\n    width: right - left,\n    height: bottom - top,\n  };\n}\n\nmodule.exports = getRangeBoundingClientRect;\n"
  },
  {
    "path": "src/component/selection/getRangeClientRects.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst UserAgent = require('UserAgent');\n\nconst invariant = require('invariant');\n\nconst isChrome = UserAgent.isBrowser('Chrome');\n\n// In Chrome, the client rects will include the entire bounds of all nodes that\n// begin (have a start tag) within the selection, even if the selection does\n// not overlap the entire node. To resolve this, we split the range at each\n// start tag and join the client rects together.\n// https://code.google.com/p/chromium/issues/detail?id=324437\nfunction getRangeClientRectsChrome(range: Range): Array<ClientRect> {\n  const tempRange = range.cloneRange();\n  const clientRects = [];\n\n  for (\n    let ancestor: ?Node = range.endContainer;\n    ancestor != null;\n    ancestor = ancestor.parentNode\n  ) {\n    // If we've climbed up to the common ancestor, we can now use the\n    // original start point and stop climbing the tree.\n    const atCommonAncestor = ancestor === range.commonAncestorContainer;\n    if (atCommonAncestor) {\n      tempRange.setStart(range.startContainer, range.startOffset);\n    } else {\n      tempRange.setStart(tempRange.endContainer, 0);\n    }\n    const rects = Array.from(tempRange.getClientRects());\n    clientRects.push(rects);\n    if (atCommonAncestor) {\n      clientRects.reverse();\n      return ([]: Array<ClientRect>).concat(...clientRects);\n    }\n    tempRange.setEndBefore(ancestor);\n  }\n\n  invariant(\n    false,\n    'Found an unexpected detached subtree when getting range client rects.',\n  );\n}\n/* eslint-enable consistent-return */\n\n/**\n * Like range.getClientRects() but normalizes for browser bugs.\n */\nconst getRangeClientRects = ((isChrome\n  ? getRangeClientRectsChrome\n  : function (range: Range): Array<ClientRect> {\n      return Array.from(range.getClientRects());\n    }): (range: Range) => Array<ClientRect>);\n\nmodule.exports = getRangeClientRects;\n"
  },
  {
    "path": "src/component/selection/getSampleSelectionMocksForTesting.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst CharacterMetadata = require('CharacterMetadata');\nconst ContentBlock = require('ContentBlock');\nconst ContentState = require('ContentState');\nconst EditorState = require('EditorState');\nconst {BOLD} = require('SampleDraftInlineStyle');\n\nconst Immutable = require('immutable');\nconst {EMPTY} = CharacterMetadata;\n\nconst getSampleSelectionMocksForTesting = (): Object => {\n  const root = document.createElement('div');\n  const contents = document.createElement('div');\n\n  contents.setAttribute('data-contents', 'true');\n  root.appendChild(contents);\n\n  const text = [\n    'Washington',\n    'Jefferson',\n    'Lincoln',\n    'Roosevelt',\n    'Kennedy',\n    'Obama',\n  ];\n\n  const textA = text[0] + text[1];\n  const textB = text[2] + text[3];\n  const textC = text[4] + text[5];\n\n  const boldChar = CharacterMetadata.create({\n    style: BOLD,\n  });\n\n  const aChars = Immutable.List(\n    Immutable.Repeat(EMPTY, text[0].length).concat(\n      Immutable.Repeat(boldChar, text[1].length),\n    ),\n  );\n\n  const bChars = Immutable.List(\n    Immutable.Repeat(EMPTY, text[2].length).concat(\n      Immutable.Repeat(boldChar, text[3].length),\n    ),\n  );\n\n  const cChars = Immutable.List(\n    Immutable.Repeat(EMPTY, text[4].length).concat(\n      Immutable.Repeat(boldChar, text[5].length),\n    ),\n  );\n\n  const contentBlocks = [\n    new ContentBlock({\n      key: 'a',\n      type: 'unstyled',\n      text: textA,\n      characterList: aChars,\n    }),\n    new ContentBlock({\n      key: 'b',\n      type: 'unstyled',\n      text: textB,\n      characterList: bChars,\n    }),\n    new ContentBlock({\n      key: 'c',\n      type: 'unstyled',\n      text: textC,\n      characterList: cChars,\n    }),\n  ];\n\n  const contentState = ContentState.createFromBlockArray(contentBlocks);\n  const editorState = EditorState.createWithContent(contentState);\n\n  const textNodes = text.map(text => {\n    return document.createTextNode(text);\n  });\n\n  const leafChildren = textNodes.map(textNode => {\n    const span = document.createElement('span');\n    span.appendChild(textNode);\n    return span;\n  });\n\n  const leafs = ['a-0-0', 'a-0-1', 'b-0-0', 'b-0-1', 'c-0-0', 'c-0-1'].map(\n    (blockKey, index) => {\n      const span = document.createElement('span');\n      span.setAttribute('data-offset-key', '' + blockKey);\n      span.appendChild(leafChildren[index]);\n      return span;\n    },\n  );\n\n  const decorators = ['a-0-0', 'b-0-0', 'c-0-0'].map((decoratorKey, index) => {\n    const span = document.createElement('span');\n    span.setAttribute('data-offset-key', '' + decoratorKey);\n    span.appendChild(leafs[index * 2]);\n    span.appendChild(leafs[index * 2 + 1]);\n    return span;\n  });\n\n  const blocks = ['a-0-0', 'b-0-0', 'c-0-0'].map((blockKey, index) => {\n    const outerBlockElement = document.createElement('div');\n    const innerBlockElement = document.createElement('div');\n\n    innerBlockElement.setAttribute('data-offset-key', '' + blockKey);\n    innerBlockElement.appendChild(decorators[index]);\n\n    outerBlockElement.setAttribute('data-offset-key', '' + blockKey);\n    outerBlockElement.setAttribute('data-block', 'true');\n    outerBlockElement.appendChild(innerBlockElement);\n\n    return outerBlockElement;\n  });\n\n  blocks.forEach(blockElem => {\n    contents.appendChild(blockElem);\n  });\n\n  return {\n    editorState,\n    root,\n    contents,\n    blocks,\n    decorators,\n    leafs,\n    leafChildren,\n    textNodes,\n  };\n};\n\nmodule.exports = getSampleSelectionMocksForTesting;\n"
  },
  {
    "path": "src/component/selection/getSampleSelectionMocksForTestingNestedBlocks.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\nimport type {BlockNodeKey} from 'BlockNode';\n\nconst ContentBlockNode = require('ContentBlockNode');\nconst ContentState = require('ContentState');\nconst EditorState = require('EditorState');\n\nconst Immutable = require('immutable');\n\nconst getSampleSelectionMocksForTestingNestedBlocks = (): Object => {\n  const root = document.createElement('div');\n  const contents = document.createElement('div');\n\n  contents.setAttribute('data-contents', 'true');\n  root.appendChild(contents);\n\n  const text = [null, 'beta', null, 'delta'];\n  const offsetKeys = ['a-0-0', 'b-0-0', 'c-0-0', 'd-0-0'];\n\n  const contentBlocks = [\n    new ContentBlockNode({\n      key: 'a',\n      nextSibling: 'c',\n      children: Immutable.List.of('b'),\n    }),\n    new ContentBlockNode({\n      key: 'b',\n      parent: 'a',\n      text: text[1],\n    }),\n    new ContentBlockNode({\n      key: 'c',\n      prevSibling: 'a',\n      children: Immutable.List.of('d'),\n    }),\n    new ContentBlockNode({\n      key: 'd',\n      parent: 'c',\n      text: text[3],\n    }),\n  ];\n\n  const contentState = ContentState.createFromBlockArray(contentBlocks);\n  const editorState = EditorState.createWithContent(contentState);\n\n  const textNodes = text.map(text => {\n    if (!text) {\n      return null;\n    }\n    return document.createTextNode(text);\n  });\n\n  const leafChildren = textNodes.map(textNode => {\n    if (!textNode) {\n      return null;\n    }\n    const span = document.createElement('span');\n    span.appendChild(textNode);\n    return span;\n  });\n\n  const leafs = leafChildren.map((leafChild, index) => {\n    if (!leafChild) {\n      return null;\n    }\n    const blockKey = offsetKeys[index];\n    const span = document.createElement('span');\n    span.setAttribute('data-offset-key', blockKey);\n    span.appendChild(leafChild);\n    return span;\n  });\n\n  const decorators = leafs.map((leaf, index) => {\n    if (!leaf) {\n      return null;\n    }\n    const blockKey = offsetKeys[index];\n    const span = document.createElement('span');\n    span.setAttribute('data-offset-key', blockKey);\n    span.appendChild(leaf);\n    return span;\n  });\n\n  const blocks = offsetKeys.map((blockKey, index) => {\n    const outerBlockElement = document.createElement('div');\n    const innerBlockElement = document.createElement('div');\n\n    innerBlockElement.setAttribute('data-offset-key', blockKey);\n    outerBlockElement.setAttribute('data-offset-key', blockKey);\n    outerBlockElement.setAttribute('data-block', 'true');\n\n    const decorator = decorators[index];\n\n    // only leaf nodes can have text\n    if (decorator) {\n      innerBlockElement.appendChild(decorator);\n    }\n\n    outerBlockElement.appendChild(innerBlockElement);\n\n    return outerBlockElement;\n  });\n\n  const blockCacheRef: {[BlockNodeKey]: HTMLDivElement} = {};\n  blocks.forEach((blockElem, index) => {\n    const currentBlock = contentBlocks[index];\n    const parentKey = currentBlock.getParentKey();\n\n    // add this block reference to the cache lookup ref\n    blockCacheRef[currentBlock.getKey()] = blockElem;\n\n    // root nodes get appended directly to the contents block\n    if (!parentKey) {\n      contents.appendChild(blockElem);\n      return;\n    }\n\n    // append to to the innerBlockElement of the parent block\n    // $FlowFixMe[incompatible-use]\n    blockCacheRef[parentKey].firstChild.appendChild(blockElem);\n  });\n\n  return {\n    editorState,\n    root,\n    contents,\n    blocks,\n    decorators,\n    leafs,\n    leafChildren,\n    textNodes,\n  };\n};\n\nmodule.exports = getSampleSelectionMocksForTestingNestedBlocks;\n"
  },
  {
    "path": "src/component/selection/getSelectionOffsetKeyForNode.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\n/**\n * Get offset key from a node or it's child nodes. Return the first offset key\n * found on the DOM tree of given node.\n */\nconst isElement = require('isElement');\n\nfunction getSelectionOffsetKeyForNode(node: Node): ?string {\n  if (isElement(node)) {\n    const castedNode: Element = (node: any);\n    const offsetKey = castedNode.getAttribute('data-offset-key');\n    if (offsetKey) {\n      return offsetKey;\n    }\n    for (let ii = 0; ii < castedNode.childNodes.length; ii++) {\n      const childOffsetKey = getSelectionOffsetKeyForNode(\n        castedNode.childNodes[ii],\n      );\n      if (childOffsetKey) {\n        return childOffsetKey;\n      }\n    }\n  }\n  return null;\n}\n\nmodule.exports = getSelectionOffsetKeyForNode;\n"
  },
  {
    "path": "src/component/selection/getUpdatedSelectionState.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type EditorState from 'EditorState';\nimport type SelectionState from 'SelectionState';\n\nconst DraftOffsetKey = require('DraftOffsetKey');\n\nconst nullthrows = require('nullthrows');\n\nfunction getUpdatedSelectionState(\n  editorState: EditorState,\n  anchorKey: string,\n  anchorOffset: number,\n  focusKey: string,\n  focusOffset: number,\n): SelectionState {\n  const selection: SelectionState = nullthrows(editorState.getSelection());\n  if (!anchorKey || !focusKey) {\n    // If we cannot make sense of the updated selection state, stick to the current one.\n    if (__DEV__) {\n      /* eslint-disable-next-line */\n      console.warn('Invalid selection state.', arguments, editorState.toJS());\n    }\n    return selection;\n  }\n\n  const anchorPath = DraftOffsetKey.decode(anchorKey);\n  const anchorBlockKey = anchorPath.blockKey;\n  const anchorLeafBlockTree = editorState.getBlockTree(anchorBlockKey);\n  const anchorLeaf =\n    anchorLeafBlockTree &&\n    anchorLeafBlockTree.getIn([\n      anchorPath.decoratorKey,\n      'leaves',\n      anchorPath.leafKey,\n    ]);\n\n  const focusPath = DraftOffsetKey.decode(focusKey);\n  const focusBlockKey = focusPath.blockKey;\n  const focusLeafBlockTree = editorState.getBlockTree(focusBlockKey);\n  const focusLeaf =\n    focusLeafBlockTree &&\n    focusLeafBlockTree.getIn([\n      focusPath.decoratorKey,\n      'leaves',\n      focusPath.leafKey,\n    ]);\n\n  if (!anchorLeaf || !focusLeaf) {\n    // If we cannot make sense of the updated selection state, stick to the current one.\n    if (__DEV__) {\n      /* eslint-disable-next-line */\n      console.warn('Invalid selection state.', arguments, editorState.toJS());\n    }\n    return selection;\n  }\n\n  const anchorLeafStart: number = anchorLeaf.get('start');\n  const focusLeafStart: number = focusLeaf.get('start');\n\n  const anchorBlockOffset = anchorLeaf ? anchorLeafStart + anchorOffset : null;\n  const focusBlockOffset = focusLeaf ? focusLeafStart + focusOffset : null;\n\n  const areEqual =\n    selection.getAnchorKey() === anchorBlockKey &&\n    selection.getAnchorOffset() === anchorBlockOffset &&\n    selection.getFocusKey() === focusBlockKey &&\n    selection.getFocusOffset() === focusBlockOffset;\n\n  if (areEqual) {\n    return selection;\n  }\n\n  let isBackward = false;\n  if (anchorBlockKey === focusBlockKey) {\n    const anchorLeafEnd: number = anchorLeaf.get('end');\n    const focusLeafEnd: number = focusLeaf.get('end');\n    if (focusLeafStart === anchorLeafStart && focusLeafEnd === anchorLeafEnd) {\n      isBackward = focusOffset < anchorOffset;\n    } else {\n      isBackward = focusLeafStart < anchorLeafStart;\n    }\n  } else {\n    const startKey = editorState\n      .getCurrentContent()\n      .getBlockMap()\n      .keySeq()\n      .skipUntil(v => v === anchorBlockKey || v === focusBlockKey)\n      .first();\n    isBackward = startKey === focusBlockKey;\n  }\n\n  return selection.merge({\n    anchorKey: anchorBlockKey,\n    anchorOffset: anchorBlockOffset,\n    focusKey: focusBlockKey,\n    focusOffset: focusBlockOffset,\n    isBackward,\n  });\n}\n\nmodule.exports = getUpdatedSelectionState;\n"
  },
  {
    "path": "src/component/selection/getVisibleSelectionRect.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {FakeClientRect} from 'getRangeBoundingClientRect';\n\nconst getRangeBoundingClientRect = require('getRangeBoundingClientRect');\n\n/**\n * Return the bounding ClientRect for the visible DOM selection, if any.\n * In cases where there are no selected ranges or the bounding rect is\n * temporarily invalid, return null.\n *\n * When using from an iframe, you should pass the iframe window object\n */\nfunction getVisibleSelectionRect(global: any): ?FakeClientRect {\n  const selection = global.getSelection();\n  if (!selection.rangeCount) {\n    return null;\n  }\n\n  const range = selection.getRangeAt(0);\n  const boundingRect = getRangeBoundingClientRect(range);\n  const {top, right, bottom, left} = boundingRect;\n\n  // When a re-render leads to a node being removed, the DOM selection will\n  // temporarily be placed on an ancestor node, which leads to an invalid\n  // bounding rect. Discard this state.\n  if (top === 0 && right === 0 && bottom === 0 && left === 0) {\n    return null;\n  }\n\n  return boundingRect;\n}\n\nmodule.exports = getVisibleSelectionRect;\n"
  },
  {
    "path": "src/component/selection/isSelectionAtLeafStart.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type EditorState from 'EditorState';\n\nfunction isSelectionAtLeafStart(editorState: EditorState): boolean {\n  const selection = editorState.getSelection();\n  const anchorKey = selection.getAnchorKey();\n  const blockTree = editorState.getBlockTree(anchorKey);\n  const offset = selection.getStartOffset();\n\n  let isAtStart = false;\n\n  blockTree.some(leafSet => {\n    if (offset === leafSet.get('start')) {\n      isAtStart = true;\n      return true;\n    }\n\n    if (offset < leafSet.get('end')) {\n      return leafSet.get('leaves').some(leaf => {\n        const leafStart = leaf.get('start');\n        if (offset === leafStart) {\n          isAtStart = true;\n          return true;\n        }\n\n        return false;\n      });\n    }\n\n    return false;\n  });\n\n  return isAtStart;\n}\n\nmodule.exports = isSelectionAtLeafStart;\n"
  },
  {
    "path": "src/component/selection/setDraftEditorSelection.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {SelectionObject} from 'DraftDOMTypes';\nimport type SelectionState from 'SelectionState';\n\nconst DraftEffects = require('DraftEffects');\nconst DraftJsDebugLogging = require('DraftJsDebugLogging');\nconst UserAgent = require('UserAgent');\n\nconst containsNode = require('containsNode');\nconst getActiveElement = require('getActiveElement');\nconst getCorrectDocumentFromNode = require('getCorrectDocumentFromNode');\nconst invariant = require('invariant');\nconst isElement = require('isElement');\n\nconst isIE = UserAgent.isBrowser('IE');\n\nfunction getAnonymizedDOM(\n  node: Node,\n  getNodeLabels?: (n: Node) => Array<string>,\n): string {\n  if (!node) {\n    return '[empty]';\n  }\n\n  const anonymized = anonymizeTextWithin(node, getNodeLabels);\n  if (anonymized.nodeType === Node.TEXT_NODE) {\n    return anonymized.textContent;\n  }\n\n  invariant(\n    isElement(anonymized),\n    'Node must be an Element if it is not a text node.',\n  );\n  const castedElement: Element = (anonymized: any);\n  return castedElement.outerHTML;\n}\n\nfunction anonymizeTextWithin(\n  node: Node,\n  getNodeLabels?: (n: Node) => Array<string>,\n): Node {\n  const labels = getNodeLabels !== undefined ? getNodeLabels(node) : [];\n\n  if (node.nodeType === Node.TEXT_NODE) {\n    const length = node.textContent.length;\n    return getCorrectDocumentFromNode(node).createTextNode(\n      '[text ' +\n        length +\n        (labels.length ? ' | ' + labels.join(', ') : '') +\n        ']',\n    );\n  }\n\n  const clone = node.cloneNode();\n  if (clone.nodeType === 1 && labels.length) {\n    ((clone: any): Element).setAttribute('data-labels', labels.join(', '));\n  }\n  const childNodes = node.childNodes;\n  for (let ii = 0; ii < childNodes.length; ii++) {\n    clone.appendChild(anonymizeTextWithin(childNodes[ii], getNodeLabels));\n  }\n\n  return clone;\n}\n\nfunction getAnonymizedEditorDOM(\n  node: Node,\n  getNodeLabels?: (n: Node) => Array<string>,\n): string {\n  // grabbing the DOM content of the Draft editor\n  let currentNode: ?Node = node;\n  // this should only be used after checking with isElement\n  let castedNode: Element = (currentNode: any);\n  while (currentNode) {\n    if (isElement(currentNode) && castedNode.hasAttribute('contenteditable')) {\n      // found the Draft editor container\n      return getAnonymizedDOM(currentNode, getNodeLabels);\n    } else {\n      currentNode = currentNode.parentNode;\n      castedNode = (currentNode: any);\n    }\n  }\n  return 'Could not find contentEditable parent of node';\n}\n\nfunction getNodeLength(node: Node): number {\n  return node.nodeValue === null\n    ? node.childNodes.length\n    : node.nodeValue.length;\n}\n\n/**\n * In modern non-IE browsers, we can support both forward and backward\n * selections.\n *\n * Note: IE10+ supports the Selection object, but it does not support\n * the `extend` method, which means that even in modern IE, it's not possible\n * to programatically create a backward selection. Thus, for all IE\n * versions, we use the old IE API to create our selections.\n */\nfunction setDraftEditorSelection(\n  selectionState: SelectionState,\n  node: Node,\n  blockKey: string,\n  nodeStart: number,\n  nodeEnd: number,\n): void {\n  // It's possible that the editor has been removed from the DOM but\n  // our selection code doesn't know it yet. Forcing selection in\n  // this case may lead to errors, so just bail now.\n  const documentObject = getCorrectDocumentFromNode(node);\n  if (!containsNode(documentObject.documentElement, node)) {\n    return;\n  }\n\n  const selection: SelectionObject = documentObject.defaultView.getSelection();\n  let anchorKey = selectionState.getAnchorKey();\n  let anchorOffset = selectionState.getAnchorOffset();\n  let focusKey = selectionState.getFocusKey();\n  let focusOffset = selectionState.getFocusOffset();\n  let isBackward = selectionState.getIsBackward();\n\n  // IE doesn't support backward selection. Swap key/offset pairs.\n  if (!selection.extend && isBackward) {\n    const tempKey = anchorKey;\n    const tempOffset = anchorOffset;\n    anchorKey = focusKey;\n    anchorOffset = focusOffset;\n    focusKey = tempKey;\n    focusOffset = tempOffset;\n    isBackward = false;\n  }\n\n  const hasAnchor =\n    anchorKey === blockKey &&\n    nodeStart <= anchorOffset &&\n    nodeEnd >= anchorOffset;\n\n  const hasFocus =\n    focusKey === blockKey && nodeStart <= focusOffset && nodeEnd >= focusOffset;\n\n  // If the selection is entirely bound within this node, set the selection\n  // and be done.\n  if (hasAnchor && hasFocus) {\n    selection.removeAllRanges();\n    addPointToSelection(\n      selection,\n      node,\n      anchorOffset - nodeStart,\n      selectionState,\n    );\n    addFocusToSelection(\n      selection,\n      node,\n      focusOffset - nodeStart,\n      selectionState,\n    );\n    return;\n  }\n\n  if (!isBackward) {\n    // If the anchor is within this node, set the range start.\n    if (hasAnchor) {\n      selection.removeAllRanges();\n      addPointToSelection(\n        selection,\n        node,\n        anchorOffset - nodeStart,\n        selectionState,\n      );\n    }\n\n    // If the focus is within this node, we can assume that we have\n    // already set the appropriate start range on the selection, and\n    // can simply extend the selection.\n    if (hasFocus) {\n      addFocusToSelection(\n        selection,\n        node,\n        focusOffset - nodeStart,\n        selectionState,\n      );\n    }\n  } else {\n    // If this node has the focus, set the selection range to be a\n    // collapsed range beginning here. Later, when we encounter the anchor,\n    // we'll use this information to extend the selection.\n    if (hasFocus) {\n      selection.removeAllRanges();\n      addPointToSelection(\n        selection,\n        node,\n        focusOffset - nodeStart,\n        selectionState,\n      );\n    }\n\n    // If this node has the anchor, we may assume that the correct\n    // focus information is already stored on the selection object.\n    // We keep track of it, reset the selection range, and extend it\n    // back to the focus point.\n    if (hasAnchor) {\n      const storedFocusNode = selection.focusNode;\n      const storedFocusOffset = selection.focusOffset;\n\n      selection.removeAllRanges();\n      addPointToSelection(\n        selection,\n        node,\n        anchorOffset - nodeStart,\n        selectionState,\n      );\n      addFocusToSelection(\n        selection,\n        storedFocusNode,\n        storedFocusOffset,\n        selectionState,\n      );\n    }\n  }\n}\n\n/**\n * Extend selection towards focus point.\n */\nfunction addFocusToSelection(\n  selection: SelectionObject,\n  node: ?Node,\n  offset: number,\n  selectionState: SelectionState,\n): void {\n  const activeElement = getActiveElement();\n  const extend = selection.extend;\n  // containsNode returns false if node is null.\n  // Let's refine the type of this value out here so flow knows.\n  if (extend && node != null && containsNode(activeElement, node)) {\n    // If `extend` is called while another element has focus, an error is\n    // thrown. We therefore disable `extend` if the active element is somewhere\n    // other than the node we are selecting. This should only occur in Firefox,\n    // since it is the only browser to support multiple selections.\n    // See https://bugzilla.mozilla.org/show_bug.cgi?id=921444.\n\n    // logging to catch bug that is being reported in t16250795\n    if (offset > getNodeLength(node)) {\n      // the call to 'selection.extend' is about to throw\n      DraftJsDebugLogging.logSelectionStateFailure({\n        anonymizedDom: getAnonymizedEditorDOM(node),\n        extraParams: JSON.stringify({offset}),\n        selectionState: JSON.stringify(selectionState.toJS()),\n      });\n    }\n\n    // logging to catch bug that is being reported in t18110632\n    const nodeWasFocus = node === selection.focusNode;\n    try {\n      // Fixes some reports of \"InvalidStateError: Failed to execute 'extend' on\n      // 'Selection': This Selection object doesn't have any Ranges.\"\n      // Note: selection.extend does not exist in IE.\n      if (selection.rangeCount > 0 && selection.extend) {\n        selection.extend(node, offset);\n      }\n    } catch (e) {\n      DraftJsDebugLogging.logSelectionStateFailure({\n        anonymizedDom: getAnonymizedEditorDOM(node, function (n) {\n          const labels = [];\n          if (n === activeElement) {\n            labels.push('active element');\n          }\n          if (n === selection.anchorNode) {\n            labels.push('selection anchor node');\n          }\n          if (n === selection.focusNode) {\n            labels.push('selection focus node');\n          }\n          return labels;\n        }),\n        extraParams: JSON.stringify(\n          {\n            activeElementName: activeElement ? activeElement.nodeName : null,\n            nodeIsFocus: node === selection.focusNode,\n            nodeWasFocus,\n            selectionRangeCount: selection.rangeCount,\n            selectionAnchorNodeName: selection.anchorNode\n              ? selection.anchorNode.nodeName\n              : null,\n            selectionAnchorOffset: selection.anchorOffset,\n            selectionFocusNodeName: selection.focusNode\n              ? selection.focusNode.nodeName\n              : null,\n            selectionFocusOffset: selection.focusOffset,\n            message: e ? '' + e : null,\n            offset,\n          },\n          null,\n          2,\n        ),\n        selectionState: JSON.stringify(selectionState.toJS(), null, 2),\n      });\n      // allow the error to be thrown -\n      // better than continuing in a broken state\n      throw e;\n    }\n  } else {\n    // IE doesn't support extend. This will mean no backward selection.\n    // Extract the existing selection range and add focus to it.\n    // Additionally, clone the selection range. IE11 throws an\n    // InvalidStateError when attempting to access selection properties\n    // after the range is detached.\n    if (node && selection.rangeCount > 0) {\n      const range = selection.getRangeAt(0);\n      range.setEnd(node, offset);\n      selection.addRange(range.cloneRange());\n    }\n  }\n}\n\nfunction addPointToSelection(\n  selection: SelectionObject,\n  node: Node,\n  offset: number,\n  selectionState: SelectionState,\n): void {\n  const range = getCorrectDocumentFromNode(node).createRange();\n  // logging to catch bug that is being reported in t16250795\n  if (offset > getNodeLength(node)) {\n    // in this case we know that the call to 'range.setStart' is about to throw\n    DraftJsDebugLogging.logSelectionStateFailure({\n      anonymizedDom: getAnonymizedEditorDOM(node),\n      extraParams: JSON.stringify({offset}),\n      selectionState: JSON.stringify(selectionState.toJS()),\n    });\n    DraftEffects.handleExtensionCausedError();\n  }\n  range.setStart(node, offset);\n\n  // IE sometimes throws Unspecified Error when trying to addRange\n  if (isIE) {\n    try {\n      selection.addRange(range);\n    } catch (e) {\n      if (__DEV__) {\n        /* eslint-disable-next-line no-console */\n        console.warn('Call to selection.addRange() threw exception: ', e);\n      }\n    }\n  } else {\n    selection.addRange(range);\n  }\n}\n\nmodule.exports = {\n  setDraftEditorSelection,\n  addFocusToSelection,\n};\n"
  },
  {
    "path": "src/component/utils/DraftDOMTypes.js",
    "content": "/**\n * (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.\n *\n * Types for things in the DOM used in Draft.js. These should eventaully be\n * added to the flow DOM lib itself.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\n// https://developer.mozilla.org/en-US/docs/Web/API/Selection\nexport type SelectionObject = {\n  /**\n   * Returns the Node in which the selection begins. Can return null if\n   * selection never existed in the document (e.g., an iframe that was\n   * never clicked on). */\n  anchorNode: ?Node,\n  anchorOffset: number,\n  focusNode: ?Node,\n  focusOffset: number,\n  isCollapsed: boolean,\n  rangeCount: number,\n  type: string,\n\n  removeAllRanges(): void,\n  getRangeAt: (index: number) => Range,\n  extend?: (node: Node, offset?: number) => void,\n  addRange: (range: Range) => void,\n  // ...etc. This is a non-exhaustive definition.\n};\n"
  },
  {
    "path": "src/component/utils/DraftStyleDefault.css",
    "content": "/**\n * (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @providesModule DraftStyleDefault\n * @format\n */\n\n.public/DraftStyleDefault/block {\n  position: relative;\n  white-space: pre-wrap;\n}\n\n/* @noflip */\n.public/DraftStyleDefault/ltr {\n  direction: ltr;\n  text-align: left;\n}\n\n/* @noflip */\n.public/DraftStyleDefault/rtl {\n  direction: rtl;\n  text-align: right;\n}\n\n/**\n * These rules provide appropriate text direction for counter pseudo-elements.\n */\n/* @noflip */\n.public/DraftStyleDefault/listLTR {\n  direction: ltr;\n}\n\n/* @noflip */\n.public/DraftStyleDefault/listRTL {\n  direction: rtl;\n}\n\n/**\n * Default spacing for list container elements. Override with CSS as needed.\n */\n.public/DraftStyleDefault/ul,\n.public/DraftStyleDefault/ol {\n  margin: 16px 0;\n  padding: 0;\n}\n\n/**\n * Default counters and styles are provided for five levels of nesting.\n * If you require nesting beyond that level, you should use your own CSS\n * classes to do so. If you care about handling RTL languages, the rules you\n * create should look a lot like these.\n */\n\n/* @noflip */\n.public/DraftStyleDefault/depth0.public/DraftStyleDefault/listLTR {\n  margin-left: 1.5em;\n}\n\n/* @noflip */\n.public/DraftStyleDefault/depth0.public/DraftStyleDefault/listRTL {\n  margin-right: 1.5em;\n}\n\n/* @noflip */\n.public/DraftStyleDefault/depth1.public/DraftStyleDefault/listLTR {\n  margin-left: 3em;\n}\n\n/* @noflip */\n.public/DraftStyleDefault/depth1.public/DraftStyleDefault/listRTL {\n  margin-right: 3em;\n}\n\n/* @noflip */\n.public/DraftStyleDefault/depth2.public/DraftStyleDefault/listLTR {\n  margin-left: 4.5em;\n}\n\n/* @noflip */\n.public/DraftStyleDefault/depth2.public/DraftStyleDefault/listRTL {\n  margin-right: 4.5em;\n}\n\n/* @noflip */\n.public/DraftStyleDefault/depth3.public/DraftStyleDefault/listLTR {\n  margin-left: 6em;\n}\n\n/* @noflip */\n.public/DraftStyleDefault/depth3.public/DraftStyleDefault/listRTL {\n  margin-right: 6em;\n}\n\n/* @noflip */\n.public/DraftStyleDefault/depth4.public/DraftStyleDefault/listLTR {\n  margin-left: 7.5em;\n}\n\n/* @noflip */\n.public/DraftStyleDefault/depth4.public/DraftStyleDefault/listRTL {\n  margin-right: 7.5em;\n}\n\n/**\n * Only use `square` list-style after the first two levels.\n */\n.public/DraftStyleDefault/unorderedListItem {\n  list-style-type: square;\n  position: relative;\n}\n\n.public/DraftStyleDefault/unorderedListItem.public/DraftStyleDefault/depth0 {\n  list-style-type: disc;\n}\n\n.public/DraftStyleDefault/unorderedListItem.public/DraftStyleDefault/depth1 {\n  list-style-type: circle;\n}\n\n/**\n * Ordered list item counters are managed with CSS, since all list nesting is\n * purely visual.\n */\n.public/DraftStyleDefault/orderedListItem {\n  list-style-type: none;\n  position: relative;\n}\n\n/* @noflip */\n.public/DraftStyleDefault/orderedListItem.public/DraftStyleDefault/listLTR:before {\n  left: -36px;\n  position: absolute;\n  text-align: right;\n  width: 30px;\n}\n\n/* @noflip */\n.public/DraftStyleDefault/orderedListItem.public/DraftStyleDefault/listRTL:before {\n  position: absolute;\n  right: -36px;\n  text-align: left;\n  width: 30px;\n}\n\n/**\n * Counters are reset in JavaScript. If you need different counter styles,\n * override these rules. If you need more nesting, create your own rules to\n * do so.\n */\n.public/DraftStyleDefault/orderedListItem:before {\n  content: counter(ol0) '. ';\n  counter-increment: ol0;\n}\n\n.public/DraftStyleDefault/orderedListItem.public/DraftStyleDefault/depth1:before {\n  content: counter(ol1, lower-alpha) '. ';\n  counter-increment: ol1;\n}\n\n.public/DraftStyleDefault/orderedListItem.public/DraftStyleDefault/depth2:before {\n  content: counter(ol2, lower-roman) '. ';\n  counter-increment: ol2;\n}\n\n.public/DraftStyleDefault/orderedListItem.public/DraftStyleDefault/depth3:before {\n  content: counter(ol3) '. ';\n  counter-increment: ol3;\n}\n\n.public/DraftStyleDefault/orderedListItem.public/DraftStyleDefault/depth4:before {\n  content: counter(ol4, lower-alpha) '. ';\n  counter-increment: ol4;\n}\n\n.public/DraftStyleDefault/depth0.public/DraftStyleDefault/reset {\n  counter-reset: ol0;\n}\n\n.public/DraftStyleDefault/depth1.public/DraftStyleDefault/reset {\n  counter-reset: ol1;\n}\n\n.public/DraftStyleDefault/depth2.public/DraftStyleDefault/reset {\n  counter-reset: ol2;\n}\n\n.public/DraftStyleDefault/depth3.public/DraftStyleDefault/reset {\n  counter-reset: ol3;\n}\n\n.public/DraftStyleDefault/depth4.public/DraftStyleDefault/reset {\n  counter-reset: ol4;\n}\n"
  },
  {
    "path": "src/component/utils/KeyBindingUtil.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst UserAgent = require('UserAgent');\n\nconst isSoftNewlineEvent = require('isSoftNewlineEvent');\n\nconst isOSX = UserAgent.isPlatform('Mac OS X');\n\nconst KeyBindingUtil = {\n  /**\n   * Check whether the ctrlKey modifier is *not* being used in conjunction with\n   * the altKey modifier. If they are combined, the result is an `altGraph`\n   * key modifier, which should not be handled by this set of key bindings.\n   */\n  isCtrlKeyCommand(e: SyntheticKeyboardEvent<>): boolean {\n    return !!e.ctrlKey && !e.altKey;\n  },\n\n  isOptionKeyCommand(e: SyntheticKeyboardEvent<>): boolean {\n    return isOSX && e.altKey;\n  },\n\n  usesMacOSHeuristics(): boolean {\n    return isOSX;\n  },\n\n  hasCommandModifier(e: SyntheticKeyboardEvent<>): boolean {\n    return isOSX\n      ? !!e.metaKey && !e.altKey\n      : KeyBindingUtil.isCtrlKeyCommand(e);\n  },\n\n  isSoftNewlineEvent,\n};\n\nmodule.exports = KeyBindingUtil;\n"
  },
  {
    "path": "src/component/utils/_DraftTestHelper.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\nconst BLACK_LIST_PROPS = ['data-reactroot'];\nconst transformSnapshotProps = (\n  node: any,\n  blackList: Array<string> = BLACK_LIST_PROPS,\n): any => {\n  const stack = [node];\n  while (stack.length) {\n    const node = stack.pop();\n    if (node.props) {\n      if (node.props.className) {\n        node.props.className = node.props.className.replace(/-/g, '__');\n      }\n      BLACK_LIST_PROPS.forEach(prop => delete node.props[prop]);\n    }\n    if (Array.isArray(node.children)) {\n      stack.push(...node.children);\n    }\n  }\n  return node;\n};\n\nconst DraftTestHelper = {\n  /**\n   * This is meant to be used in combination with ReactTestRenderer\n   * to ensure compatibility with running our snapshot tests internally\n   *\n   * usage example:\n   *\n   * const blockNode = ReactTestRenderer.create(\n   *  <DraftComponentFooBar {...childProps} />,\n   * );\n   *\n   * expect(transformSnapshotProps(blockNode.toJSON())).toMatchSnapshot();\n   */\n  transformSnapshotProps,\n};\n\nmodule.exports = DraftTestHelper;\n"
  },
  {
    "path": "src/component/utils/__tests__/isHTMLBRElement-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst isHTMLBRElement = require('isHTMLBRElement');\n\ntest('isHTMLBRElement recognizes null', () => {\n  expect(isHTMLBRElement(null)).toBe(false);\n});\n\ntest('isHTMLBRElement recognizes BR elements in same document', () => {\n  const br = document.createElement('br');\n  expect(isHTMLBRElement(br)).toBe(true);\n});\n\ntest('isHTMLBRElement recognizes BR elements in iframed document', () => {\n  const iframe = document.createElement('iframe');\n  if (document.body != null) {\n    document.body.appendChild(iframe);\n    const doc = iframe.contentDocument;\n    const br = doc.createElement('br');\n    expect(isHTMLBRElement(br)).toBe(true);\n  }\n});\n"
  },
  {
    "path": "src/component/utils/draftKeyUtils.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * Provides utilities for handling draftjs keys.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nfunction notEmptyKey(key: ?string): boolean %checks {\n  return key != null && key != '';\n}\n\nmodule.exports = {\n  notEmptyKey,\n};\n"
  },
  {
    "path": "src/component/utils/exploration/DraftTreeAdapter.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * This is unstable and not part of the public API and should not be used by\n * production systems. This file may be update/removed without notice.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\nimport type {DraftBlockType} from 'DraftBlockType';\nimport type {EntityRange} from 'EntityRange';\nimport type {InlineStyleRange} from 'InlineStyleRange';\nimport type {RawDraftContentBlock} from 'RawDraftContentBlock';\nimport type {RawDraftContentState} from 'RawDraftContentState';\n\nconst generateRandomKey = require('generateRandomKey');\nconst invariant = require('invariant');\n\nconst traverseInDepthOrder = (\n  blocks: Array<RawDraftContentBlock>,\n  fn: (block: RawDraftContentBlock) => void,\n) => {\n  let stack = [...blocks].reverse();\n  while (stack.length) {\n    const block = stack.pop();\n\n    fn(block);\n\n    const children = block.children;\n\n    invariant(Array.isArray(children), 'Invalid tree raw block');\n\n    stack = stack.concat([...children.reverse()]);\n  }\n};\n\nconst isListBlock = (block?: RawDraftContentBlock): boolean => {\n  if (!(block && block.type)) {\n    return false;\n  }\n  const {type} = block;\n  return type === 'unordered-list-item' || type === 'ordered-list-item';\n};\n\nconst addDepthToChildren = (block: RawDraftContentBlock) => {\n  if (Array.isArray(block.children)) {\n    block.children = block.children.map(child =>\n      child.type === block.type\n        ? {...child, depth: (block.depth || 0) + 1}\n        : child,\n    );\n  }\n};\n\n/**\n * This adapter is intended to be be used as an adapter to draft tree data\n *\n * draft state <=====> draft tree state\n */\nconst DraftTreeAdapter = {\n  /**\n   * Converts from a tree raw state back to draft raw state\n   */\n  fromRawTreeStateToRawState(\n    draftTreeState: RawDraftContentState,\n  ): RawDraftContentState {\n    const {blocks} = draftTreeState;\n    const transformedBlocks = [];\n\n    invariant(Array.isArray(blocks), 'Invalid raw state');\n\n    if (!Array.isArray(blocks) || !blocks.length) {\n      return draftTreeState;\n    }\n\n    traverseInDepthOrder(blocks, block => {\n      const newBlock = {\n        ...block,\n      };\n\n      if (isListBlock(block)) {\n        newBlock.depth = newBlock.depth || 0;\n        addDepthToChildren(block);\n\n        // if it's a non-leaf node, we don't do anything else\n        if (block.children != null && block.children.length > 0) {\n          return;\n        }\n      }\n\n      delete newBlock.children;\n\n      transformedBlocks.push(newBlock);\n    });\n\n    draftTreeState.blocks = transformedBlocks;\n\n    return {\n      ...draftTreeState,\n      blocks: transformedBlocks,\n    };\n  },\n\n  /**\n   * Converts from draft raw state to tree draft state\n   */\n  fromRawStateToRawTreeState(\n    draftState: RawDraftContentState,\n  ): RawDraftContentState {\n    const transformedBlocks: Array<RawDraftContentBlock> = [];\n    const parentStack: Array<{\n      children: Array<RawDraftContentBlock>,\n      depth: number,\n      entityRanges: Array<EntityRange>,\n      inlineStyleRanges: Array<InlineStyleRange>,\n      key: string,\n      text: string,\n      type: DraftBlockType,\n    }> = [];\n\n    draftState.blocks.forEach(block => {\n      const isList = isListBlock(block);\n      const depth = block.depth || 0;\n      const treeBlock = {\n        ...block,\n        children: ([]: Array<RawDraftContentBlock>),\n      };\n\n      if (!isList) {\n        transformedBlocks.push(treeBlock);\n        return;\n      }\n\n      let lastParent = parentStack[0];\n      // block is non-nested & there are no nested blocks, directly push block\n      if (lastParent == null && depth === 0) {\n        transformedBlocks.push(treeBlock);\n        // block is first nested block or previous nested block is at a lower level\n      } else if (lastParent == null || lastParent.depth < depth - 1) {\n        // create new parent block\n        const newParent = {\n          key: generateRandomKey(),\n          text: '',\n          depth: depth - 1,\n          type: block.type,\n          children: ([]: Array<RawDraftContentBlock>),\n          entityRanges: ([]: Array<EntityRange>),\n          inlineStyleRanges: ([]: Array<InlineStyleRange>),\n        };\n\n        parentStack.unshift(newParent);\n        if (depth === 1) {\n          // add as a root-level block\n          transformedBlocks.push(newParent);\n        } else if (lastParent != null) {\n          // depth > 1 => also add as previous parent's child\n          lastParent.children.push(newParent);\n        }\n        newParent.children.push(treeBlock);\n      } else if (lastParent.depth === depth - 1) {\n        // add as child of last parent\n        lastParent.children.push(treeBlock);\n      } else {\n        // pop out parents at levels above this one from the parent stack\n        while (lastParent != null && lastParent.depth >= depth) {\n          parentStack.shift();\n          lastParent = parentStack[0];\n        }\n        if (depth > 0) {\n          lastParent.children.push(treeBlock);\n        } else {\n          transformedBlocks.push(treeBlock);\n        }\n      }\n    });\n\n    return {\n      ...draftState,\n      blocks: transformedBlocks,\n    };\n  },\n};\n\nmodule.exports = DraftTreeAdapter;\n"
  },
  {
    "path": "src/component/utils/exploration/DraftTreeInvariants.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * This is unstable and not part of the public API and should not be used by\n * production systems. This file may be update/removed without notice.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\nimport type {BlockMap} from 'BlockMap';\nimport type {BlockNodeKey} from 'BlockNode';\nimport type ContentBlockNode from 'ContentBlockNode';\n\nconst warning = require('warning');\n\nconst DraftTreeInvariants = {\n  /**\n   * Check if the block is valid\n   */\n  isValidBlock(block: ContentBlockNode, blockMap: BlockMap): boolean {\n    const key = block.getKey();\n    // is its parent's child\n    const parentKey = block.getParentKey();\n    if (parentKey != null) {\n      const parent = blockMap.get(parentKey);\n      if (!parent.getChildKeys().includes(key)) {\n        warning(true, 'Tree is missing parent -> child pointer on %s', key);\n        return false;\n      }\n    }\n\n    // is its children's parent\n    const children = block.getChildKeys().map(k => blockMap.get(k));\n    if (!children.every(c => c.getParentKey() === key)) {\n      warning(true, 'Tree is missing child -> parent pointer on %s', key);\n      return false;\n    }\n\n    // is its previous sibling's next sibling\n    const prevSiblingKey = block.getPrevSiblingKey();\n    if (prevSiblingKey != null) {\n      const prevSibling = blockMap.get(prevSiblingKey);\n      if (prevSibling.getNextSiblingKey() !== key) {\n        warning(\n          true,\n          \"Tree is missing nextSibling pointer on %s's prevSibling\",\n          key,\n        );\n        return false;\n      }\n    }\n\n    // is its next sibling's previous sibling\n    const nextSiblingKey = block.getNextSiblingKey();\n    if (nextSiblingKey != null) {\n      const nextSibling = blockMap.get(nextSiblingKey);\n      if (nextSibling.getPrevSiblingKey() !== key) {\n        warning(\n          true,\n          \"Tree is missing prevSibling pointer on %s's nextSibling\",\n          key,\n        );\n        return false;\n      }\n    }\n\n    // no 2-node cycles\n    if (nextSiblingKey !== null && prevSiblingKey !== null) {\n      if (prevSiblingKey === nextSiblingKey) {\n        warning(true, 'Tree has a two-node cycle at %s', key);\n        return false;\n      }\n    }\n\n    // if it's a leaf node, it has text but no children\n    if (block.text != '') {\n      if (block.getChildKeys().size > 0) {\n        warning(true, 'Leaf node %s has children', key);\n        return false;\n      }\n    }\n    return true;\n  },\n\n  /**\n   * Checks that this is a connected tree on all the blocks\n   * starting from the first block, traversing nextSibling and child pointers\n   * should be a tree (preorder traversal - parent, then children)\n   * num of connected node === number of blocks\n   */\n  isConnectedTree(blockMap: BlockMap): boolean {\n    // exactly one node has no previous sibling + no parent\n    const eligibleFirstNodes = blockMap\n      .toArray()\n      .filter(\n        block =>\n          block.getParentKey() == null && block.getPrevSiblingKey() == null,\n      );\n    if (eligibleFirstNodes.length !== 1) {\n      warning(true, 'Tree is not connected. More or less than one first node');\n      return false;\n    }\n    const firstNode = eligibleFirstNodes.shift();\n    let nodesSeen = 0;\n    let currentKey: ?($FlowFixMe | BlockNodeKey) = firstNode.getKey();\n    const visitedStack: Array<$FlowFixMe | BlockNodeKey> = [];\n    while (currentKey != null) {\n      const currentNode = blockMap.get(currentKey);\n      const childKeys = currentNode.getChildKeys();\n      const nextSiblingKey = currentNode.getNextSiblingKey();\n      // if the node has children, add parent's next sibling to stack and go to children\n      if (childKeys.size > 0) {\n        if (nextSiblingKey != null) {\n          visitedStack.unshift(nextSiblingKey);\n        }\n        const children = childKeys.map(k => blockMap.get(k));\n        const firstNode = children.find(\n          block => block.getPrevSiblingKey() == null,\n        );\n        if (firstNode == null) {\n          warning(true, '%s has no first child', currentKey);\n          return false;\n        }\n        currentKey = firstNode.getKey();\n        // TODO(T32490138): Deal with multi-node cycles here\n      } else {\n        if (currentNode.getNextSiblingKey() != null) {\n          currentKey = currentNode.getNextSiblingKey();\n        } else {\n          currentKey = visitedStack.shift();\n        }\n      }\n      nodesSeen++;\n    }\n\n    if (nodesSeen !== blockMap.size) {\n      warning(\n        true,\n        'Tree is not connected. %s nodes were seen instead of %s',\n        nodesSeen,\n        blockMap.size,\n      );\n      return false;\n    }\n\n    return true;\n  },\n\n  /**\n   * Checks that the block map is a connected tree with valid blocks\n   */\n  isValidTree(blockMap: BlockMap): boolean {\n    const blocks = blockMap.toArray();\n    if (\n      !blocks.every(block => DraftTreeInvariants.isValidBlock(block, blockMap))\n    ) {\n      return false;\n    }\n    return DraftTreeInvariants.isConnectedTree(blockMap);\n  },\n};\n\nmodule.exports = DraftTreeInvariants;\n"
  },
  {
    "path": "src/component/utils/exploration/__tests__/DraftTreeAdapter-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\njest.mock('generateRandomKey');\n\nconst DraftTreeAdapter = require('DraftTreeAdapter');\n\nconst assertFromRawTreeStateToRawState = rawState => {\n  expect(\n    DraftTreeAdapter.fromRawTreeStateToRawState(rawState),\n  ).toMatchSnapshot();\n};\n\nconst assertFromRawStateToRawTreeState = rawState => {\n  expect(\n    DraftTreeAdapter.fromRawStateToRawTreeState(rawState),\n  ).toMatchSnapshot();\n};\n\ntest('must be able to convert from tree raw state with only root blocks to raw state', () => {\n  const rawState = {\n    blocks: [\n      {\n        key: 'A',\n        text: 'Alpha',\n        children: [],\n      },\n      {\n        key: 'B',\n        text: 'Beta',\n        children: [],\n      },\n    ],\n    entityMap: {},\n  };\n\n  assertFromRawTreeStateToRawState(rawState);\n});\n\ntest('must be able to convert from tree raw state with nested blocks to raw state', () => {\n  // Right now, we ignore non-list nested blocks\n  const rawState = {\n    blocks: [\n      {\n        key: 'A',\n        type: 'blockquote',\n        text: '',\n        children: [\n          {\n            key: 'B',\n            text: 'Beta',\n            type: 'header-one',\n            children: [],\n          },\n          {\n            key: 'C',\n            text: 'Charlie',\n            type: 'header-two',\n            children: [],\n          },\n        ],\n      },\n    ],\n    entityMap: {},\n  };\n\n  assertFromRawTreeStateToRawState(rawState);\n});\n\ntest('must be able to convert from tree raw state with nested list blocks to raw state preserving lists depth', () => {\n  /**\n   * 1. Alpha\n   *   a. Beta\n   *     i. Charlie\n   *   b. Delta\n   */\n  const rawState = {\n    blocks: [\n      {\n        key: 'A',\n        type: 'ordered-list-item',\n        text: 'Alpha',\n        children: [],\n      },\n      {\n        key: 'X',\n        text: '',\n        type: 'ordered-list-item',\n        children: [\n          {\n            key: 'B',\n            type: 'ordered-list-item',\n            text: 'Beta',\n            children: [],\n          },\n          {\n            key: 'Y',\n            type: 'ordered-list-item',\n            text: '',\n            children: [\n              {\n                key: 'C',\n                text: 'Charlie',\n                type: 'ordered-list-item',\n                children: [],\n              },\n            ],\n          },\n          {\n            key: 'D',\n            text: 'Delta',\n            type: 'ordered-list-item',\n            children: [],\n          },\n        ],\n      },\n    ],\n    entityMap: {},\n  };\n\n  assertFromRawTreeStateToRawState(rawState);\n});\n\ntest('must be able to convert from tree raw state with nested list blocks to raw state preserving lists depth only if type matches', () => {\n  const rawState = {\n    blocks: [\n      {\n        key: 'A',\n        type: 'ordered-list-item',\n        text: 'Alpha',\n        children: [],\n      },\n      {\n        key: 'X',\n        type: 'ordered-list-item',\n        text: '',\n        children: [\n          {\n            key: 'B',\n            text: 'Beta',\n            type: 'ordered-list-item',\n            children: [],\n          },\n          {\n            key: 'Y',\n            type: 'ordered-list-item',\n            text: '',\n            children: [\n              {\n                key: 'C',\n                text: 'Charlie',\n                type: 'unordered-list-item',\n                children: [],\n              },\n            ],\n          },\n        ],\n      },\n    ],\n    entityMap: {},\n  };\n\n  assertFromRawTreeStateToRawState(rawState);\n});\n\ntest('must be able to convert from raw state to raw tree state', () => {\n  const rawState = {\n    blocks: [\n      {\n        key: 'A',\n        text: 'Alpha',\n      },\n      {\n        key: 'B',\n        text: 'Beta',\n      },\n      {\n        key: 'C',\n        text: 'Charlie',\n      },\n    ],\n    entityMap: {},\n  };\n\n  assertFromRawStateToRawTreeState(rawState);\n});\n\ntest('must be able to convert from raw state to raw tree state with nested trees based on lists depth', () => {\n  const rawState = {\n    blocks: [\n      {\n        key: 'A',\n        text: 'Alpha',\n        type: 'ordered-list-item',\n        depth: 0,\n      },\n      {\n        key: 'B',\n        text: 'Beta',\n        type: 'ordered-list-item',\n        depth: 1,\n      },\n      {\n        key: 'C',\n        text: 'Charlie',\n        type: 'ordered-list-item',\n        depth: 2,\n      },\n      {\n        key: 'D',\n        text: 'Delta',\n        type: 'ordered-list-item',\n        depth: 1,\n      },\n    ],\n    entityMap: {},\n  };\n\n  assertFromRawStateToRawTreeState(rawState);\n});\n\ntest('must be able to convert from raw state to raw tree state with nested trees based on lists depth and attach nested blocks to closest depth parent', () => {\n  const rawState = {\n    blocks: [\n      {\n        key: 'A',\n        text: 'Alpha',\n        type: 'ordered-list-item',\n        depth: 0,\n      },\n      {\n        key: 'B',\n        text: 'Beta',\n        type: 'ordered-list-item',\n        depth: 1,\n      },\n      {\n        key: 'C',\n        text: 'Charlie',\n        type: 'ordered-list-item',\n        depth: 1,\n      },\n      {\n        key: 'D',\n        text: 'Delta',\n        type: 'ordered-list-item',\n        depth: 2,\n      },\n    ],\n    entityMap: {},\n  };\n\n  assertFromRawStateToRawTreeState(rawState);\n});\n\ntest('must be able to convert from raw state to raw tree state with nested trees of various depths', () => {\n  const rawState = {\n    blocks: [\n      {\n        key: 'A',\n        text: 'alpha',\n        type: 'unordered-list-item',\n        depth: 0,\n      },\n      {\n        key: 'B',\n        text: 'beta',\n        type: 'unordered-list-item',\n        depth: 1,\n      },\n      {\n        key: 'C',\n        text: 'charlie',\n        type: 'unordered-list-item',\n        depth: 1,\n      },\n      {\n        key: 'D',\n        text: 'delta',\n        type: 'unordered-list-item',\n        depth: 2,\n      },\n      {\n        key: 'E',\n        text: 'epsilon',\n        type: 'unordered-list-item',\n        depth: 1,\n      },\n      {\n        key: 'F',\n        text: 'foo',\n        type: 'unordered-list-item',\n        depth: 2,\n      },\n      {\n        key: 'G',\n        text: 'gamma',\n        type: 'unordered-list-item',\n        depth: 3,\n      },\n      {\n        key: 'H',\n        text: 'house',\n        type: 'unordered-list-item',\n        depth: 1,\n      },\n      {\n        key: 'I',\n        text: 'iota',\n        type: 'unordered-list-item',\n        depth: 0,\n      },\n    ],\n    entityMap: {},\n  };\n\n  assertFromRawStateToRawTreeState(rawState);\n});\n"
  },
  {
    "path": "src/component/utils/exploration/__tests__/DraftTreeInvariants-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\n// missing parent -> child connection\n\nconst ContentBlockNode = require('ContentBlockNode');\nconst DraftTreeInvariants = require('DraftTreeInvariants');\n\nconst Immutable = require('immutable');\n\ntest('single block', () =>\n  expect(\n    DraftTreeInvariants.isValidTree(\n      Immutable.OrderedMap({\n        A: new ContentBlockNode({\n          key: 'A',\n          parent: null,\n          text: 'Charlie',\n          children: Immutable.List([]),\n          prevSibling: null,\n          nextSibling: null,\n        }),\n      }),\n    ),\n  ).toBe(true));\n\n// valid trees with children and siblings\ntest('simple valid tree', () =>\n  expect(\n    DraftTreeInvariants.isValidTree(\n      Immutable.OrderedMap({\n        A: new ContentBlockNode({\n          key: 'A',\n          parent: null,\n          text: 'alpha',\n          children: Immutable.List([]),\n          prevSibling: null,\n          nextSibling: 'B',\n        }),\n        B: new ContentBlockNode({\n          key: 'B',\n          parent: null,\n          text: '',\n          children: Immutable.List(['C', 'D']),\n          prevSibling: 'A',\n          nextSibling: 'E',\n        }),\n        C: new ContentBlockNode({\n          key: 'C',\n          parent: 'B',\n          text: 'charlie',\n          children: Immutable.List([]),\n          prevSibling: null,\n          nextSibling: 'D',\n        }),\n        D: new ContentBlockNode({\n          key: 'D',\n          parent: 'B',\n          text: 'delta',\n          children: Immutable.List([]),\n          prevSibling: 'C',\n          nextSibling: null,\n        }),\n        E: new ContentBlockNode({\n          key: 'E',\n          parent: null,\n          text: 'epsilon',\n          children: Immutable.List([]),\n          prevSibling: 'B',\n          nextSibling: null,\n        }),\n      }),\n    ),\n  ).toBe(true));\n\ntest('complex valid tree', () =>\n  expect(\n    DraftTreeInvariants.isValidTree(\n      Immutable.OrderedMap({\n        A: new ContentBlockNode({\n          key: 'A',\n          parent: null,\n          text: '',\n          children: Immutable.List(['B', 'D', 'Z']),\n          prevSibling: 'X',\n          nextSibling: 'C',\n        }),\n        B: new ContentBlockNode({\n          key: 'B',\n          parent: 'A',\n          text: 'beta',\n          children: Immutable.List([]),\n          prevSibling: null,\n          nextSibling: 'D',\n        }),\n        C: new ContentBlockNode({\n          key: 'C',\n          parent: null,\n          text: 'charlie',\n          children: Immutable.List([]),\n          prevSibling: 'A',\n          nextSibling: null,\n        }),\n        D: new ContentBlockNode({\n          key: 'D',\n          parent: 'A',\n          text: '',\n          children: Immutable.List(['E', 'G', 'F']),\n          prevSibling: 'B',\n          nextSibling: 'Z',\n        }),\n        E: new ContentBlockNode({\n          key: 'E',\n          parent: 'D',\n          text: 'epsilon',\n          children: Immutable.List([]),\n          prevSibling: null,\n          nextSibling: 'F',\n        }),\n        F: new ContentBlockNode({\n          key: 'F',\n          parent: 'D',\n          text: 'fish',\n          children: Immutable.List([]),\n          prevSibling: 'E',\n          nextSibling: 'G',\n        }),\n        G: new ContentBlockNode({\n          key: 'G',\n          parent: 'D',\n          text: 'gamma',\n          children: Immutable.List([]),\n          prevSibling: 'F',\n          nextSibling: null,\n        }),\n        X: new ContentBlockNode({\n          key: 'X',\n          parent: null,\n          text: '',\n          children: Immutable.List(['Y']),\n          prevSibling: null,\n          nextSibling: 'A',\n        }),\n        Y: new ContentBlockNode({\n          key: 'Y',\n          parent: 'X',\n          text: 'yeti',\n          children: Immutable.List([]),\n          prevSibling: null,\n          nextSibling: null,\n        }),\n        Z: new ContentBlockNode({\n          key: 'Z',\n          parent: 'A',\n          text: 'zeta',\n          children: Immutable.List([]),\n          prevSibling: 'D',\n          nextSibling: null,\n        }),\n      }),\n    ),\n  ).toBe(true));\n\ntest('missing child -> parent pointer', () =>\n  expect(\n    DraftTreeInvariants.isValidTree(\n      Immutable.OrderedMap({\n        A: new ContentBlockNode({\n          key: 'A',\n          parent: null,\n          text: 'alpha',\n          children: Immutable.List([]),\n          prevSibling: null,\n          nextSibling: 'B',\n        }),\n        B: new ContentBlockNode({\n          key: 'B',\n          parent: null,\n          text: '',\n          children: Immutable.List(['C', 'D']),\n          prevSibling: 'A',\n          nextSibling: 'E',\n        }),\n        C: new ContentBlockNode({\n          key: 'C',\n          parent: 'B',\n          text: 'charlie',\n          children: Immutable.List([]),\n          prevSibling: null,\n          nextSibling: 'D',\n        }),\n        D: new ContentBlockNode({\n          key: 'D',\n          parent: null, // should be B\n          text: 'delta',\n          children: Immutable.List([]),\n          prevSibling: 'C',\n          nextSibling: null,\n        }),\n        E: new ContentBlockNode({\n          key: 'E',\n          parent: null,\n          text: 'epsilon',\n          children: Immutable.List([]),\n          prevSibling: 'B',\n          nextSibling: null,\n        }),\n      }),\n    ),\n  ).toBe(false));\n\ntest('missing parent -> child pointer', () =>\n  expect(\n    DraftTreeInvariants.isValidTree(\n      Immutable.OrderedMap({\n        A: new ContentBlockNode({\n          key: 'A',\n          parent: null,\n          text: 'alpha',\n          children: Immutable.List([]),\n          prevSibling: null,\n          nextSibling: 'B',\n        }),\n        B: new ContentBlockNode({\n          key: 'B',\n          parent: null,\n          text: '',\n          children: Immutable.List(['C']), // should be [C, D]\n          prevSibling: 'A',\n          nextSibling: 'E',\n        }),\n        C: new ContentBlockNode({\n          key: 'C',\n          parent: 'B',\n          text: 'charlie',\n          children: Immutable.List([]),\n          prevSibling: null,\n          nextSibling: 'D',\n        }),\n        D: new ContentBlockNode({\n          key: 'D',\n          parent: 'B',\n          text: 'delta',\n          children: Immutable.List([]),\n          prevSibling: 'C',\n          nextSibling: null,\n        }),\n        E: new ContentBlockNode({\n          key: 'E',\n          parent: null,\n          text: 'epsilon',\n          children: Immutable.List([]),\n          prevSibling: 'B',\n          nextSibling: null,\n        }),\n      }),\n    ),\n  ).toBe(false));\n\n// missing prevSibling\ntest('missing prev pointer', () =>\n  expect(\n    DraftTreeInvariants.isValidTree(\n      Immutable.OrderedMap({\n        A: new ContentBlockNode({\n          key: 'A',\n          parent: null,\n          text: 'alpha',\n          children: Immutable.List([]),\n          prevSibling: null,\n          nextSibling: 'B',\n        }),\n        B: new ContentBlockNode({\n          key: 'B',\n          parent: null,\n          text: '',\n          children: Immutable.List(['C', 'D']),\n          prevSibling: 'A',\n          nextSibling: 'E',\n        }),\n        C: new ContentBlockNode({\n          key: 'C',\n          parent: 'B',\n          text: 'charlie',\n          children: Immutable.List([]),\n          prevSibling: null,\n          nextSibling: 'D',\n        }),\n        D: new ContentBlockNode({\n          key: 'D',\n          parent: 'B',\n          text: 'delta',\n          children: Immutable.List([]),\n          prevSibling: null, // should be D\n          nextSibling: null,\n        }),\n        E: new ContentBlockNode({\n          key: 'E',\n          parent: null,\n          text: 'epsilon',\n          children: Immutable.List([]),\n          prevSibling: 'B',\n          nextSibling: null,\n        }),\n      }),\n    ),\n  ).toBe(false));\n\n// missing nextSibling\ntest('missing nextSibling pointer', () =>\n  expect(\n    DraftTreeInvariants.isValidTree(\n      Immutable.OrderedMap({\n        A: new ContentBlockNode({\n          key: 'A',\n          parent: null,\n          text: 'alpha',\n          children: Immutable.List([]),\n          prevSibling: null,\n          nextSibling: 'B',\n        }),\n        B: new ContentBlockNode({\n          key: 'B',\n          parent: null,\n          text: '',\n          children: Immutable.List(['C', 'D']),\n          prevSibling: 'A',\n          nextSibling: null, // should be E\n        }),\n        C: new ContentBlockNode({\n          key: 'C',\n          parent: 'B',\n          text: 'charlie',\n          children: Immutable.List([]),\n          prevSibling: null,\n          nextSibling: 'D',\n        }),\n        D: new ContentBlockNode({\n          key: 'D',\n          parent: 'B',\n          text: 'delta',\n          children: Immutable.List([]),\n          prevSibling: 'C',\n          nextSibling: null,\n        }),\n        E: new ContentBlockNode({\n          key: 'E',\n          parent: null,\n          text: 'epsilon',\n          children: Immutable.List([]),\n          prevSibling: 'B',\n          nextSibling: null,\n        }),\n      }),\n    ),\n  ).toBe(false));\n\n// two-node cycle C <-> D\ntest('missing child -> parent connection', () =>\n  expect(\n    DraftTreeInvariants.isValidTree(\n      Immutable.OrderedMap({\n        A: new ContentBlockNode({\n          key: 'A',\n          parent: null,\n          text: 'alpha',\n          children: Immutable.List([]),\n          prevSibling: null,\n          nextSibling: 'B',\n        }),\n        B: new ContentBlockNode({\n          key: 'B',\n          parent: null,\n          text: '',\n          children: Immutable.List(['C', 'D']),\n          prevSibling: 'A',\n          nextSibling: 'E',\n        }),\n        C: new ContentBlockNode({\n          key: 'C',\n          parent: 'B',\n          text: 'charlie',\n          children: Immutable.List([]),\n          prevSibling: 'D', // should be null\n          nextSibling: 'D',\n        }),\n        D: new ContentBlockNode({\n          key: 'D',\n          parent: 'B',\n          text: 'delta',\n          children: Immutable.List([]),\n          prevSibling: 'C',\n          nextSibling: 'C', // should be null\n        }),\n        E: new ContentBlockNode({\n          key: 'E',\n          parent: null,\n          text: 'epsilon',\n          children: Immutable.List([]),\n          prevSibling: 'B',\n          nextSibling: null,\n        }),\n      }),\n    ),\n  ).toBe(false));\n\n// leaf has children\ntest('missing child -> parent connection', () =>\n  expect(\n    DraftTreeInvariants.isValidTree(\n      Immutable.OrderedMap({\n        A: new ContentBlockNode({\n          key: 'A',\n          parent: null,\n          text: 'alpha',\n          children: Immutable.List([]),\n          prevSibling: null,\n          nextSibling: 'B',\n        }),\n        B: new ContentBlockNode({\n          key: 'B',\n          parent: null,\n          text: '',\n          children: Immutable.List(['C', 'D']),\n          prevSibling: 'A',\n          nextSibling: 'E',\n        }),\n        C: new ContentBlockNode({\n          key: 'C',\n          parent: 'B',\n          text: 'charlie', // should be ''\n          children: Immutable.List(['F']),\n          prevSibling: null,\n          nextSibling: 'D',\n        }),\n        D: new ContentBlockNode({\n          key: 'D',\n          parent: 'B',\n          text: 'delta',\n          children: Immutable.List([]),\n          prevSibling: 'C',\n          nextSibling: null,\n        }),\n        E: new ContentBlockNode({\n          key: 'E',\n          parent: null,\n          text: 'epsilon',\n          children: Immutable.List([]),\n          prevSibling: 'B',\n          nextSibling: null,\n        }),\n        F: new ContentBlockNode({\n          key: 'F',\n          parent: 'C',\n          text: 'fish',\n          children: Immutable.List([]),\n          prevSibling: null,\n          nextSibling: null,\n        }),\n      }),\n    ),\n  ).toBe(false));\n\n// unconnected tree (two clusters not connected by parent-child pointers)\ntest('unconnected tree', () =>\n  expect(\n    DraftTreeInvariants.isValidTree(\n      Immutable.OrderedMap({\n        A: new ContentBlockNode({\n          key: 'A',\n          parent: null,\n          text: '',\n          children: Immutable.List(['B', 'Z']), // should be [B, D, Z]\n          prevSibling: 'X',\n          nextSibling: 'C',\n        }),\n        B: new ContentBlockNode({\n          key: 'B',\n          parent: 'A',\n          text: 'beta',\n          children: Immutable.List([]),\n          prevSibling: null,\n          nextSibling: 'Z',\n        }),\n        C: new ContentBlockNode({\n          key: 'C',\n          parent: null,\n          text: 'charlie',\n          children: Immutable.List([]),\n          prevSibling: 'A',\n          nextSibling: null,\n        }),\n        D: new ContentBlockNode({\n          key: 'D',\n          parent: null,\n          text: '',\n          children: Immutable.List(['E', 'G', 'F']),\n          prevSibling: null,\n          nextSibling: null,\n        }),\n        E: new ContentBlockNode({\n          key: 'E',\n          parent: 'D',\n          text: 'epsilon',\n          children: Immutable.List([]),\n          prevSibling: null,\n          nextSibling: 'F',\n        }),\n        F: new ContentBlockNode({\n          key: 'F',\n          parent: 'D',\n          text: 'fish',\n          children: Immutable.List([]),\n          prevSibling: 'E',\n          nextSibling: 'G',\n        }),\n        G: new ContentBlockNode({\n          key: 'G',\n          parent: 'D',\n          text: 'gamma',\n          children: Immutable.List([]),\n          prevSibling: 'F',\n          nextSibling: null,\n        }),\n        X: new ContentBlockNode({\n          key: 'X',\n          parent: null,\n          text: '',\n          children: Immutable.List(['Y']),\n          prevSibling: null,\n          nextSibling: 'A',\n        }),\n        Y: new ContentBlockNode({\n          key: 'Y',\n          parent: 'X',\n          text: 'yeti',\n          children: Immutable.List([]),\n          prevSibling: null,\n          nextSibling: null,\n        }),\n        Z: new ContentBlockNode({\n          key: 'Z',\n          parent: 'A',\n          text: 'zeta',\n          children: Immutable.List([]),\n          prevSibling: 'B',\n          nextSibling: null,\n        }),\n      }),\n    ),\n  ).toBe(false));\n"
  },
  {
    "path": "src/component/utils/exploration/__tests__/__snapshots__/DraftTreeAdapter-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must be able to convert from raw state to raw tree state 1`] = `\nObject {\n  \"blocks\": Array [\n    Object {\n      \"children\": Array [],\n      \"key\": \"A\",\n      \"text\": \"Alpha\",\n    },\n    Object {\n      \"children\": Array [],\n      \"key\": \"B\",\n      \"text\": \"Beta\",\n    },\n    Object {\n      \"children\": Array [],\n      \"key\": \"C\",\n      \"text\": \"Charlie\",\n    },\n  ],\n  \"entityMap\": Object {},\n}\n`;\n\nexports[`must be able to convert from raw state to raw tree state with nested trees based on lists depth 1`] = `\nObject {\n  \"blocks\": Array [\n    Object {\n      \"children\": Array [],\n      \"depth\": 0,\n      \"key\": \"A\",\n      \"text\": \"Alpha\",\n      \"type\": \"ordered-list-item\",\n    },\n    Object {\n      \"children\": Array [\n        Object {\n          \"children\": Array [],\n          \"depth\": 1,\n          \"key\": \"B\",\n          \"text\": \"Beta\",\n          \"type\": \"ordered-list-item\",\n        },\n        Object {\n          \"children\": Array [\n            Object {\n              \"children\": Array [],\n              \"depth\": 2,\n              \"key\": \"C\",\n              \"text\": \"Charlie\",\n              \"type\": \"ordered-list-item\",\n            },\n          ],\n          \"depth\": 1,\n          \"entityRanges\": Array [],\n          \"inlineStyleRanges\": Array [],\n          \"key\": \"key1\",\n          \"text\": \"\",\n          \"type\": \"ordered-list-item\",\n        },\n        Object {\n          \"children\": Array [],\n          \"depth\": 1,\n          \"key\": \"D\",\n          \"text\": \"Delta\",\n          \"type\": \"ordered-list-item\",\n        },\n      ],\n      \"depth\": 0,\n      \"entityRanges\": Array [],\n      \"inlineStyleRanges\": Array [],\n      \"key\": \"key0\",\n      \"text\": \"\",\n      \"type\": \"ordered-list-item\",\n    },\n  ],\n  \"entityMap\": Object {},\n}\n`;\n\nexports[`must be able to convert from raw state to raw tree state with nested trees based on lists depth and attach nested blocks to closest depth parent 1`] = `\nObject {\n  \"blocks\": Array [\n    Object {\n      \"children\": Array [],\n      \"depth\": 0,\n      \"key\": \"A\",\n      \"text\": \"Alpha\",\n      \"type\": \"ordered-list-item\",\n    },\n    Object {\n      \"children\": Array [\n        Object {\n          \"children\": Array [],\n          \"depth\": 1,\n          \"key\": \"B\",\n          \"text\": \"Beta\",\n          \"type\": \"ordered-list-item\",\n        },\n        Object {\n          \"children\": Array [],\n          \"depth\": 1,\n          \"key\": \"C\",\n          \"text\": \"Charlie\",\n          \"type\": \"ordered-list-item\",\n        },\n        Object {\n          \"children\": Array [\n            Object {\n              \"children\": Array [],\n              \"depth\": 2,\n              \"key\": \"D\",\n              \"text\": \"Delta\",\n              \"type\": \"ordered-list-item\",\n            },\n          ],\n          \"depth\": 1,\n          \"entityRanges\": Array [],\n          \"inlineStyleRanges\": Array [],\n          \"key\": \"key3\",\n          \"text\": \"\",\n          \"type\": \"ordered-list-item\",\n        },\n      ],\n      \"depth\": 0,\n      \"entityRanges\": Array [],\n      \"inlineStyleRanges\": Array [],\n      \"key\": \"key2\",\n      \"text\": \"\",\n      \"type\": \"ordered-list-item\",\n    },\n  ],\n  \"entityMap\": Object {},\n}\n`;\n\nexports[`must be able to convert from raw state to raw tree state with nested trees of various depths 1`] = `\nObject {\n  \"blocks\": Array [\n    Object {\n      \"children\": Array [],\n      \"depth\": 0,\n      \"key\": \"A\",\n      \"text\": \"alpha\",\n      \"type\": \"unordered-list-item\",\n    },\n    Object {\n      \"children\": Array [\n        Object {\n          \"children\": Array [],\n          \"depth\": 1,\n          \"key\": \"B\",\n          \"text\": \"beta\",\n          \"type\": \"unordered-list-item\",\n        },\n        Object {\n          \"children\": Array [],\n          \"depth\": 1,\n          \"key\": \"C\",\n          \"text\": \"charlie\",\n          \"type\": \"unordered-list-item\",\n        },\n        Object {\n          \"children\": Array [\n            Object {\n              \"children\": Array [],\n              \"depth\": 2,\n              \"key\": \"D\",\n              \"text\": \"delta\",\n              \"type\": \"unordered-list-item\",\n            },\n          ],\n          \"depth\": 1,\n          \"entityRanges\": Array [],\n          \"inlineStyleRanges\": Array [],\n          \"key\": \"key5\",\n          \"text\": \"\",\n          \"type\": \"unordered-list-item\",\n        },\n        Object {\n          \"children\": Array [],\n          \"depth\": 1,\n          \"key\": \"E\",\n          \"text\": \"epsilon\",\n          \"type\": \"unordered-list-item\",\n        },\n        Object {\n          \"children\": Array [\n            Object {\n              \"children\": Array [],\n              \"depth\": 2,\n              \"key\": \"F\",\n              \"text\": \"foo\",\n              \"type\": \"unordered-list-item\",\n            },\n            Object {\n              \"children\": Array [\n                Object {\n                  \"children\": Array [],\n                  \"depth\": 3,\n                  \"key\": \"G\",\n                  \"text\": \"gamma\",\n                  \"type\": \"unordered-list-item\",\n                },\n              ],\n              \"depth\": 2,\n              \"entityRanges\": Array [],\n              \"inlineStyleRanges\": Array [],\n              \"key\": \"key7\",\n              \"text\": \"\",\n              \"type\": \"unordered-list-item\",\n            },\n          ],\n          \"depth\": 1,\n          \"entityRanges\": Array [],\n          \"inlineStyleRanges\": Array [],\n          \"key\": \"key6\",\n          \"text\": \"\",\n          \"type\": \"unordered-list-item\",\n        },\n        Object {\n          \"children\": Array [],\n          \"depth\": 1,\n          \"key\": \"H\",\n          \"text\": \"house\",\n          \"type\": \"unordered-list-item\",\n        },\n      ],\n      \"depth\": 0,\n      \"entityRanges\": Array [],\n      \"inlineStyleRanges\": Array [],\n      \"key\": \"key4\",\n      \"text\": \"\",\n      \"type\": \"unordered-list-item\",\n    },\n    Object {\n      \"children\": Array [],\n      \"depth\": 0,\n      \"key\": \"I\",\n      \"text\": \"iota\",\n      \"type\": \"unordered-list-item\",\n    },\n  ],\n  \"entityMap\": Object {},\n}\n`;\n\nexports[`must be able to convert from tree raw state with nested blocks to raw state 1`] = `\nObject {\n  \"blocks\": Array [\n    Object {\n      \"key\": \"A\",\n      \"text\": \"\",\n      \"type\": \"blockquote\",\n    },\n    Object {\n      \"key\": \"B\",\n      \"text\": \"Beta\",\n      \"type\": \"header-one\",\n    },\n    Object {\n      \"key\": \"C\",\n      \"text\": \"Charlie\",\n      \"type\": \"header-two\",\n    },\n  ],\n  \"entityMap\": Object {},\n}\n`;\n\nexports[`must be able to convert from tree raw state with nested list blocks to raw state preserving lists depth 1`] = `\nObject {\n  \"blocks\": Array [\n    Object {\n      \"depth\": 0,\n      \"key\": \"A\",\n      \"text\": \"Alpha\",\n      \"type\": \"ordered-list-item\",\n    },\n    Object {\n      \"depth\": 1,\n      \"key\": \"B\",\n      \"text\": \"Beta\",\n      \"type\": \"ordered-list-item\",\n    },\n    Object {\n      \"depth\": 2,\n      \"key\": \"C\",\n      \"text\": \"Charlie\",\n      \"type\": \"ordered-list-item\",\n    },\n    Object {\n      \"depth\": 1,\n      \"key\": \"D\",\n      \"text\": \"Delta\",\n      \"type\": \"ordered-list-item\",\n    },\n  ],\n  \"entityMap\": Object {},\n}\n`;\n\nexports[`must be able to convert from tree raw state with nested list blocks to raw state preserving lists depth only if type matches 1`] = `\nObject {\n  \"blocks\": Array [\n    Object {\n      \"depth\": 0,\n      \"key\": \"A\",\n      \"text\": \"Alpha\",\n      \"type\": \"ordered-list-item\",\n    },\n    Object {\n      \"depth\": 1,\n      \"key\": \"B\",\n      \"text\": \"Beta\",\n      \"type\": \"ordered-list-item\",\n    },\n    Object {\n      \"depth\": 0,\n      \"key\": \"C\",\n      \"text\": \"Charlie\",\n      \"type\": \"unordered-list-item\",\n    },\n  ],\n  \"entityMap\": Object {},\n}\n`;\n\nexports[`must be able to convert from tree raw state with only root blocks to raw state 1`] = `\nObject {\n  \"blocks\": Array [\n    Object {\n      \"key\": \"A\",\n      \"text\": \"Alpha\",\n    },\n    Object {\n      \"key\": \"B\",\n      \"text\": \"Beta\",\n    },\n  ],\n  \"entityMap\": Object {},\n}\n`;\n"
  },
  {
    "path": "src/component/utils/getContentEditableContainer.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type DraftEditor from 'DraftEditor.react';\n\nconst invariant = require('invariant');\nconst isHTMLElement = require('isHTMLElement');\n\nfunction getContentEditableContainer(editor: DraftEditor): HTMLElement {\n  const editorNode = editor.editorContainer;\n  invariant(editorNode, 'Missing editorNode');\n  invariant(\n    isHTMLElement(editorNode.firstChild),\n    'editorNode.firstChild is not an HTMLElement',\n  );\n  const htmlElement = (editorNode.firstChild: any);\n  return htmlElement;\n}\n\nmodule.exports = getContentEditableContainer;\n"
  },
  {
    "path": "src/component/utils/getCorrectDocumentFromNode.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\nfunction getCorrectDocumentFromNode(node: ?Node): Document {\n  if (!node || !node.ownerDocument) {\n    return document;\n  }\n  return node.ownerDocument;\n}\n\nmodule.exports = getCorrectDocumentFromNode;\n"
  },
  {
    "path": "src/component/utils/getDefaultKeyBinding.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {DraftEditorCommand} from 'DraftEditorCommand';\n\nconst KeyBindingUtil = require('KeyBindingUtil');\nconst Keys = require('Keys');\nconst UserAgent = require('UserAgent');\n\nconst isOSX = UserAgent.isPlatform('Mac OS X');\n\n// Firefox on OSX had a bug resulting in navigation instead of cursor movement.\n// This bug was fixed in Firefox 29. Feature detection is virtually impossible\n// so we just check the version number. See #342765.\nconst shouldFixFirefoxMovement = isOSX && UserAgent.isBrowser('Firefox < 29');\n\nconst {hasCommandModifier, isCtrlKeyCommand} = KeyBindingUtil;\n\nfunction shouldRemoveWord(e: SyntheticKeyboardEvent<>): boolean {\n  return (isOSX && e.altKey) || isCtrlKeyCommand(e);\n}\n\n/**\n * Get the appropriate undo/redo command for a Z key command.\n */\nfunction getZCommand(e: SyntheticKeyboardEvent<>): ?DraftEditorCommand {\n  if (!hasCommandModifier(e)) {\n    return null;\n  }\n  return e.shiftKey ? 'redo' : 'undo';\n}\n\nfunction getDeleteCommand(e: SyntheticKeyboardEvent<>): ?DraftEditorCommand {\n  // Allow default \"cut\" behavior for PCs on Shift + Delete.\n  if (!isOSX && e.shiftKey) {\n    return null;\n  }\n  return shouldRemoveWord(e) ? 'delete-word' : 'delete';\n}\n\nfunction getBackspaceCommand(e: SyntheticKeyboardEvent<>): ?DraftEditorCommand {\n  if (hasCommandModifier(e) && isOSX) {\n    return 'backspace-to-start-of-line';\n  }\n  return shouldRemoveWord(e) ? 'backspace-word' : 'backspace';\n}\n\n/**\n * Retrieve a bound key command for the given event.\n */\nfunction getDefaultKeyBinding(\n  e: SyntheticKeyboardEvent<>,\n): ?DraftEditorCommand {\n  switch (e.keyCode) {\n    case 66: // B\n      return hasCommandModifier(e) ? 'bold' : null;\n    case 68: // D\n      return isCtrlKeyCommand(e) ? 'delete' : null;\n    case 72: // H\n      return isCtrlKeyCommand(e) ? 'backspace' : null;\n    case 73: // I\n      return hasCommandModifier(e) ? 'italic' : null;\n    case 74: // J\n      return hasCommandModifier(e) ? 'code' : null;\n    case 75: // K\n      return isOSX && isCtrlKeyCommand(e) ? 'secondary-cut' : null;\n    case 77: // M\n      return isCtrlKeyCommand(e) ? 'split-block' : null;\n    case 79: // O\n      return isCtrlKeyCommand(e) ? 'split-block' : null;\n    case 84: // T\n      return isOSX && isCtrlKeyCommand(e) ? 'transpose-characters' : null;\n    case 85: // U\n      return hasCommandModifier(e) ? 'underline' : null;\n    case 87: // W\n      return isOSX && isCtrlKeyCommand(e) ? 'backspace-word' : null;\n    case 88: // X\n      return hasCommandModifier(e) && e.shiftKey ? 'strikethrough' : null;\n    case 89: // Y\n      if (isCtrlKeyCommand(e)) {\n        return isOSX ? 'secondary-paste' : 'redo';\n      }\n      return null;\n    case 90: // Z\n      return getZCommand(e) || null;\n    case Keys.RETURN:\n      return 'split-block';\n    case Keys.DELETE:\n      return getDeleteCommand(e);\n    case Keys.BACKSPACE:\n      return getBackspaceCommand(e);\n    // LEFT/RIGHT handlers serve as a workaround for a Firefox bug.\n    case Keys.LEFT:\n      return shouldFixFirefoxMovement && hasCommandModifier(e)\n        ? 'move-selection-to-start-of-block'\n        : null;\n    case Keys.RIGHT:\n      return shouldFixFirefoxMovement && hasCommandModifier(e)\n        ? 'move-selection-to-end-of-block'\n        : null;\n    default:\n      return null;\n  }\n}\n\nmodule.exports = getDefaultKeyBinding;\n"
  },
  {
    "path": "src/component/utils/getTextContentFromFiles.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst invariant = require('invariant');\n\nconst TEXT_CLIPPING_REGEX = /\\.textClipping$/;\n\nconst TEXT_TYPES = {\n  'text/plain': true,\n  'text/html': true,\n  'text/rtf': true,\n};\n\n// Somewhat arbitrary upper bound on text size. Let's not lock up the browser.\nconst TEXT_SIZE_UPPER_BOUND = 5000;\n\n/**\n * Extract the text content from a file list.\n */\nfunction getTextContentFromFiles(\n  files: Array<File>,\n  callback: (contents: string) => void,\n): void {\n  let readCount = 0;\n  const results = [];\n  files.forEach(function (/*blob*/ file) {\n    readFile(file, function (/*string*/ text) {\n      readCount++;\n      text && results.push(text.slice(0, TEXT_SIZE_UPPER_BOUND));\n      if (readCount == files.length) {\n        callback(results.join('\\r'));\n      }\n    });\n  });\n}\n\n/**\n * todo isaac: Do work to turn html/rtf into a content fragment.\n */\nfunction readFile(file: File, callback: (contents: string) => void): void {\n  if (!global.FileReader || (file.type && !(file.type in TEXT_TYPES))) {\n    callback('');\n    return;\n  }\n\n  if (file.type === '') {\n    let contents = '';\n    // Special-case text clippings, which have an empty type but include\n    // `.textClipping` in the file name. `readAsText` results in an empty\n    // string for text clippings, so we force the file name to serve\n    // as the text value for the file.\n    if (TEXT_CLIPPING_REGEX.test(file.name)) {\n      contents = file.name.replace(TEXT_CLIPPING_REGEX, '');\n    }\n    callback(contents);\n    return;\n  }\n\n  const reader = new FileReader();\n  reader.onload = function () {\n    const result = reader.result;\n    invariant(\n      typeof result === 'string',\n      'We should be calling \"FileReader.readAsText\" which returns a string',\n    );\n    callback(result);\n  };\n  reader.onerror = function () {\n    callback('');\n  };\n  reader.readAsText(file);\n}\n\nmodule.exports = getTextContentFromFiles;\n"
  },
  {
    "path": "src/component/utils/getWindowForNode.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\nfunction getWindowForNode(node: ?Node): Window {\n  if (!node || !node.ownerDocument || !node.ownerDocument.defaultView) {\n    return window;\n  }\n  return node.ownerDocument.defaultView;\n}\n\nmodule.exports = getWindowForNode;\n"
  },
  {
    "path": "src/component/utils/isElement.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\nfunction isElement(node: ?Node): boolean {\n  if (!node || !node.ownerDocument) {\n    return false;\n  }\n  return node.nodeType === Node.ELEMENT_NODE;\n}\n\nmodule.exports = isElement;\n"
  },
  {
    "path": "src/component/utils/isEventHandled.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {DraftHandleValue} from 'DraftHandleValue';\n\n/**\n * Utility method for determining whether or not the value returned\n * from a handler indicates that it was handled.\n */\nfunction isEventHandled(value: DraftHandleValue): boolean {\n  return value === 'handled' || value === true;\n}\n\nmodule.exports = isEventHandled;\n"
  },
  {
    "path": "src/component/utils/isHTMLAnchorElement.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\nconst isElement = require('isElement');\n\nfunction isHTMLAnchorElement(node: ?Node): boolean {\n  if (!node || !node.ownerDocument) {\n    return false;\n  }\n  return isElement(node) && node.nodeName === 'A';\n}\n\nmodule.exports = isHTMLAnchorElement;\n"
  },
  {
    "path": "src/component/utils/isHTMLBRElement.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\nconst isElement = require('isElement');\n\nfunction isHTMLBRElement(node: ?Node): boolean {\n  if (!node || !node.ownerDocument) {\n    return false;\n  }\n  return isElement(node) && node.nodeName === 'BR';\n}\n\nmodule.exports = isHTMLBRElement;\n"
  },
  {
    "path": "src/component/utils/isHTMLElement.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\nfunction isHTMLElement(node: ?Node): boolean {\n  if (!node || !node.ownerDocument) {\n    return false;\n  }\n  if (!node.ownerDocument.defaultView) {\n    return node instanceof HTMLElement;\n  }\n  if (node instanceof node.ownerDocument.defaultView.HTMLElement) {\n    return true;\n  }\n  return false;\n}\n\nmodule.exports = isHTMLElement;\n"
  },
  {
    "path": "src/component/utils/isHTMLImageElement.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\nconst isElement = require('isElement');\n\nfunction isHTMLImageElement(node: ?Node): boolean {\n  if (!node || !node.ownerDocument) {\n    return false;\n  }\n  return isElement(node) && node.nodeName === 'IMG';\n}\n\nmodule.exports = isHTMLImageElement;\n"
  },
  {
    "path": "src/component/utils/isInstanceOfNode.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\nfunction isInstanceOfNode(target: ?EventTarget): boolean {\n  // we changed the name because of having duplicate module provider (fbjs)\n  if (!target || !('ownerDocument' in target)) {\n    return false;\n  }\n  if ('ownerDocument' in target) {\n    const node: Node = (target: any);\n    if (!node.ownerDocument.defaultView) {\n      return node instanceof Node;\n    }\n    if (node instanceof node.ownerDocument.defaultView.Node) {\n      return true;\n    }\n  }\n  return false;\n}\n\nmodule.exports = isInstanceOfNode;\n"
  },
  {
    "path": "src/component/utils/isSoftNewlineEvent.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst Keys = require('Keys');\n\nfunction isSoftNewlineEvent(e: SyntheticKeyboardEvent<>): boolean {\n  return (\n    e.which === Keys.RETURN &&\n    (e.getModifierState('Shift') ||\n      e.getModifierState('Alt') ||\n      e.getModifierState('Control'))\n  );\n}\n\nmodule.exports = isSoftNewlineEvent;\n"
  },
  {
    "path": "src/component/utils/splitTextIntoTextBlocks.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst NEWLINE_REGEX = /\\r\\n?|\\n/g;\n\nfunction splitTextIntoTextBlocks(text: string): Array<string> {\n  return text.split(NEWLINE_REGEX);\n}\n\nmodule.exports = splitTextIntoTextBlocks;\n"
  },
  {
    "path": "src/flowlib/window.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n */\n\ndeclare type Window = any;\n"
  },
  {
    "path": "src/model/constants/DraftBlockType.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\n/**\n * The list of default valid block types.\n */\nexport type CoreDraftBlockType =\n  | 'unstyled'\n  | 'paragraph'\n  | 'header-one'\n  | 'header-two'\n  | 'header-three'\n  | 'header-four'\n  | 'header-five'\n  | 'header-six'\n  | 'unordered-list-item'\n  | 'ordered-list-item'\n  | 'blockquote'\n  | 'code-block'\n  | 'atomic'\n  | 'section'\n  | 'article';\n\n/**\n * User defined types can be of any valid string.\n */\nexport type CustomBlockType = string;\n\nexport type DraftBlockType = CoreDraftBlockType | CustomBlockType;\n"
  },
  {
    "path": "src/model/constants/DraftDragType.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\n/**\n * A type that allows us to avoid passing boolean arguments\n * around to indicate whether a drag type is internal or external.\n */\nexport type DraftDragType = 'internal' | 'external';\n"
  },
  {
    "path": "src/model/constants/DraftEditorCommand.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\n/**\n * A set of editor commands that may be invoked by keyboard commands or UI\n * controls. These commands should map to operations that modify content or\n * selection state and update the editor state accordingly.\n */\nexport type DraftEditorCommand =\n  /**\n   * Self-explanatory.\n   */\n  | 'undo'\n  | 'redo'\n\n  /**\n   * Perform a forward deletion.\n   */\n  | 'delete'\n\n  /**\n   * Perform a forward deletion to the next word boundary after the selection.\n   */\n  | 'delete-word'\n\n  /**\n   * Perform a backward deletion.\n   */\n  | 'backspace'\n\n  /**\n   * Perform a backward deletion to the previous word boundary before the\n   * selection.\n   */\n  | 'backspace-word'\n\n  /**\n   * Perform a backward deletion to the beginning of the current line.\n   */\n  | 'backspace-to-start-of-line'\n\n  /**\n   * Toggle styles. Commands may be intepreted to modify inline text ranges\n   * or block types.\n   */\n  | 'bold'\n  | 'italic'\n  | 'underline'\n  | 'strikethrough'\n  | 'code'\n\n  /**\n   * Split a block in two.\n   */\n  | 'split-block'\n\n  /**\n   * Self-explanatory.\n   */\n  | 'transpose-characters'\n  | 'move-selection-to-start-of-block'\n  | 'move-selection-to-end-of-block'\n\n  /**\n   * Commands to support the \"secondary\" clipboard provided by certain\n   * browsers and operating systems.\n   */\n  | 'secondary-cut'\n  | 'secondary-paste';\n"
  },
  {
    "path": "src/model/constants/DraftHandleValue.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\n/**\n * A type that allows us to avoid returning boolean values\n * to indicate whether an event was handled or not.\n */\nexport type DraftHandleValue = 'handled' | 'not-handled' | boolean;\n"
  },
  {
    "path": "src/model/constants/DraftInsertionType.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\n/**\n * A type that defines if an fragment shall be inserted before or after\n * another fragment or if the selected fragment shall be replaced\n */\nexport type DraftInsertionType = 'replace' | 'before' | 'after';\n"
  },
  {
    "path": "src/model/constants/DraftRemovalDirection.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\n/**\n * A type that allows us to avoid passing boolean arguments\n * around to indicate whether a deletion is forward or backward.\n */\nexport type DraftRemovalDirection = 'backward' | 'forward';\n"
  },
  {
    "path": "src/model/decorators/CompositeDraftDecorator.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type ContentState from 'ContentState';\nimport type {DraftDecorator} from 'DraftDecorator';\n\nconst Immutable = require('immutable');\n\nconst {List} = Immutable;\n\nconst DELIMITER = '.';\n\n/**\n * A CompositeDraftDecorator traverses through a list of DraftDecorator\n * instances to identify sections of a ContentBlock that should be rendered\n * in a \"decorated\" manner. For example, hashtags, mentions, and links may\n * be intended to stand out visually, be rendered as anchors, etc.\n *\n * The list of decorators supplied to the constructor will be used in the\n * order they are provided. This allows the caller to specify a priority for\n * string matching, in case of match collisions among decorators.\n *\n * For instance, I may have a link with a `#` in its text. Though this section\n * of text may match our hashtag decorator, it should not be treated as a\n * hashtag. I should therefore list my link DraftDecorator\n * before my hashtag DraftDecorator when constructing this composite\n * decorator instance.\n *\n * Thus, when a collision like this is encountered, the earlier match is\n * preserved and the new match is discarded.\n */\nclass CompositeDraftDecorator {\n  _decorators: $ReadOnlyArray<DraftDecorator>;\n\n  constructor(decorators: $ReadOnlyArray<DraftDecorator>) {\n    // Copy the decorator array, since we use this array order to determine\n    // precedence of decoration matching. If the array is mutated externally,\n    // we don't want to be affected here.\n    this._decorators = decorators.slice();\n  }\n\n  /**\n   * Returns true if this CompositeDraftDecorator has the same decorators as\n   * the given array. This does a reference check, so the decorators themselves\n   * have to be the same objects.\n   */\n  isCompositionOfDecorators(arr: $ReadOnlyArray<DraftDecorator>): boolean {\n    if (this._decorators.length !== arr.length) {\n      return false;\n    }\n    for (let ii = 0; ii < arr.length; ii++) {\n      if (this._decorators[ii] !== arr[ii]) {\n        return false;\n      }\n    }\n    return true;\n  }\n\n  getDecorators(): $ReadOnlyArray<DraftDecorator> {\n    return this._decorators;\n  }\n\n  getDecorations(\n    block: BlockNodeRecord,\n    contentState: ContentState,\n  ): List<?string> {\n    const decorations = Array(block.getText().length).fill(null);\n\n    this._decorators.forEach((decorator: DraftDecorator, ii: number) => {\n      let counter = 0;\n      const strategy = decorator.strategy;\n      function getDecorationsChecker(start: number, end: number) {\n        // Find out if any of our matching range is already occupied\n        // by another decorator. If so, discard the match. Otherwise, store\n        // the component key for rendering.\n        if (canOccupySlice(decorations, start, end)) {\n          occupySlice(decorations, start, end, ii + DELIMITER + counter);\n          counter++;\n        }\n      }\n      strategy(block, getDecorationsChecker, contentState);\n    });\n\n    return List(decorations);\n  }\n\n  getComponentForKey(key: string): Function {\n    const componentKey = parseInt(key.split(DELIMITER)[0], 10);\n    return this._decorators[componentKey].component;\n  }\n\n  getPropsForKey(key: string): ?Object {\n    const componentKey = parseInt(key.split(DELIMITER)[0], 10);\n    return this._decorators[componentKey].props;\n  }\n}\n\n/**\n * Determine whether we can occupy the specified slice of the decorations\n * array.\n */\nfunction canOccupySlice(\n  decorations: Array<?string>,\n  start: number,\n  end: number,\n): boolean {\n  for (let ii = start; ii < end; ii++) {\n    if (decorations[ii] != null) {\n      return false;\n    }\n  }\n  return true;\n}\n\n/**\n * Splice the specified component into our decoration array at the desired\n * range.\n */\nfunction occupySlice(\n  targetArr: Array<?string>,\n  start: number,\n  end: number,\n  componentKey: string,\n): void {\n  for (let ii = start; ii < end; ii++) {\n    targetArr[ii] = componentKey;\n  }\n}\n\nmodule.exports = CompositeDraftDecorator;\n"
  },
  {
    "path": "src/model/decorators/DraftDecorator.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeKey} from 'BlockNode';\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type ContentState from 'ContentState';\nimport type {HTMLDir} from 'UnicodeBidiDirection';\n\nconst React = require('react');\n\nexport type DraftDecoratorStrategy = (\n  block: BlockNodeRecord,\n  callback: (start: number, end: number) => void,\n  contentState: ContentState,\n) => void;\n\n/**\n * A DraftDecorator is a strategy-component pair intended for use when\n * rendering content.\n *\n *   - A \"strategy\": A function that accepts a ContentBlock object and\n *     continuously executes a callback with start/end values corresponding to\n *     relevant matches in the document text. For example, getHashtagMatches\n *     uses a hashtag regex to find hashtag strings in the block, and\n *     for each hashtag match, executes the callback with start/end pairs.\n *\n *   - A \"component\": A React component that will be used to render the\n *     \"decorated\" section of text.\n *\n *   - \"props\": Props to be passed into the React component that will be used.\n */\nexport type DraftDecorator = {\n  strategy: DraftDecoratorStrategy,\n  component: Function,\n  props?: Object,\n  ...\n};\n\n/**\n * DraftDecoratorComponentProps are the core set of props that will be\n * passed to all DraftDecoratorComponents if a Custom Block Component is not used.\n * Note that a component may also accept additional props outside of this list.\n */\nexport type DraftDecoratorComponentProps = {\n  blockKey: BlockNodeKey,\n  children?: Array<React.MixedElement>,\n  contentState: ContentState,\n  decoratedText: string,\n  dir: ?HTMLDir,\n  end: number,\n  // Many folks mistakenly assume that there will always be an 'entityKey'\n  // passed to a DecoratorComponent.\n  // To find the `entityKey`, Draft calls\n  // `contentBlock.getEntityKeyAt(leafNode)` and in many cases the leafNode does\n  // not have an entityKey. In those cases the entityKey will be null or\n  // undefined. That's why `getEntityKeyAt()` is typed to return `?string`.\n  // See https://github.com/facebook/draft-js/blob/2da3dcb1c4c106d1b2a0f07b3d0275b8d724e777/src/model/immutable/BlockNode.js#L51\n  entityKey: ?string,\n  offsetKey: string,\n  start: number,\n};\n"
  },
  {
    "path": "src/model/decorators/DraftDecoratorType.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type ContentState from 'ContentState';\nimport type {List} from 'immutable';\n\n/**\n * An interface for document decorator classes, allowing the creation of\n * custom decorator classes.\n *\n * See `CompositeDraftDecorator` for the most common use case.\n */\nexport type DraftDecoratorType = interface {\n  /**\n   * Given a `ContentBlock`, return an immutable List of decorator keys.\n   */\n  getDecorations(\n    block: BlockNodeRecord,\n    contentState: ContentState,\n  ): List<?string>,\n  /**\n   * Given a decorator key, return the component to use when rendering\n   * this decorated range.\n   */\n  getComponentForKey(key: string): Function,\n  /**\n   * Given a decorator key, optionally return the props to use when rendering\n   * this decorated range.\n   */\n  getPropsForKey(key: string): ?Object,\n};\n"
  },
  {
    "path": "src/model/decorators/__tests__/CompositeDraftDecorator-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @format\n * @oncall draft_js\n */\n\njest.mock('ContentState');\n\nconst CompositeDraftDecorator = require('CompositeDraftDecorator');\nconst ContentState = require('ContentState');\n\nclass ContentBlock {\n  constructor(text) {\n    this._text = text;\n  }\n\n  getText() {\n    return this._text;\n  }\n}\n\nconst searchWith = regex => (block, callback, contentState) => {\n  block.getText().replace(regex, (match, offset) => {\n    callback(offset, offset + match.length);\n  });\n};\n\nconst BarDecorator = {\n  strategy: searchWith(/bar/gi),\n};\n\nconst BartDecorator = {\n  strategy: searchWith(/bart/gi),\n};\n\nconst FooDecorator = {\n  strategy: searchWith(/foo/gi),\n};\n\nconst assertCompositeDraftDecorator = (\n  text,\n  decorators = [FooDecorator, BarDecorator],\n) => {\n  expect(\n    new CompositeDraftDecorator(decorators).getDecorations(\n      new ContentBlock(text),\n      ContentState.createFromText(text),\n    ),\n  ).toMatchSnapshot();\n};\n\ntest('must behave correctly if there are no matches', () => {\n  assertCompositeDraftDecorator('take a sad song and make it better');\n});\n\ntest('must find decoration matches', () => {\n  assertCompositeDraftDecorator('a footballing fool');\n});\n\ntest('must find matches for multiple decorators', () => {\n  // Match the \"Foo\" decorator and \"Bar\" decorator.\n  assertCompositeDraftDecorator('a foosball bar');\n});\n\n// Reverse the order of the matches from above. \"foo\" comes after \"bar\" in\n// the document text.\ntest('must find matches regardless of text location', () => {\n  // Match the \"Foo\" decorator and \"Bar\" decorator.\n  assertCompositeDraftDecorator('some bar food');\n});\n\ntest('must throw out overlaps with existing decorations', () => {\n  // Even though \"bart\" matches our \"bar\" strategy, \"bart\" comes first\n  // in our decoration order and will claim those letters first.\n  assertCompositeDraftDecorator('bart has a bar', [\n    BartDecorator,\n    BarDecorator,\n  ]);\n});\n\n// Swap the order of \"bar\" and \"bart\".\ntest('must throw out matches if earlier match is shorter', () => {\n  // There are no \"bart\" matches, since \"bar\" has claimed the relevant\n  // strings.\n  assertCompositeDraftDecorator('bart has a bar', [\n    BarDecorator,\n    BartDecorator,\n  ]);\n});\n\ntest('must separate adjacent ranges that have the same decorator', () => {\n  assertCompositeDraftDecorator('barbarbar', [BarDecorator]);\n});\n"
  },
  {
    "path": "src/model/decorators/__tests__/__snapshots__/CompositeDraftDecorator-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must behave correctly if there are no matches 1`] = `\nImmutable.List [\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n]\n`;\n\nexports[`must find decoration matches 1`] = `\nImmutable.List [\n  null,\n  null,\n  \"0.0\",\n  \"0.0\",\n  \"0.0\",\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  \"0.1\",\n  \"0.1\",\n  \"0.1\",\n  null,\n]\n`;\n\nexports[`must find matches for multiple decorators 1`] = `\nImmutable.List [\n  null,\n  null,\n  \"0.0\",\n  \"0.0\",\n  \"0.0\",\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  \"1.0\",\n  \"1.0\",\n  \"1.0\",\n]\n`;\n\nexports[`must find matches regardless of text location 1`] = `\nImmutable.List [\n  null,\n  null,\n  null,\n  null,\n  null,\n  \"1.0\",\n  \"1.0\",\n  \"1.0\",\n  null,\n  \"0.0\",\n  \"0.0\",\n  \"0.0\",\n  null,\n]\n`;\n\nexports[`must separate adjacent ranges that have the same decorator 1`] = `\nImmutable.List [\n  \"0.0\",\n  \"0.0\",\n  \"0.0\",\n  \"0.1\",\n  \"0.1\",\n  \"0.1\",\n  \"0.2\",\n  \"0.2\",\n  \"0.2\",\n]\n`;\n\nexports[`must throw out matches if earlier match is shorter 1`] = `\nImmutable.List [\n  \"0.0\",\n  \"0.0\",\n  \"0.0\",\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  \"0.1\",\n  \"0.1\",\n  \"0.1\",\n]\n`;\n\nexports[`must throw out overlaps with existing decorations 1`] = `\nImmutable.List [\n  \"0.0\",\n  \"0.0\",\n  \"0.0\",\n  \"0.0\",\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  \"1.0\",\n  \"1.0\",\n  \"1.0\",\n]\n`;\n"
  },
  {
    "path": "src/model/encoding/DraftStringKey.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst DraftStringKey = {\n  stringify(key: ?string): string {\n    return '_' + String(key);\n  },\n\n  unstringify(key: string): string {\n    return key.slice(1);\n  },\n};\n\nmodule.exports = DraftStringKey;\n"
  },
  {
    "path": "src/model/encoding/EntityRange.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\n/**\n * A plain object representation of an entity attribution.\n *\n * The `key` value corresponds to the key of the entity in the `entityMap` of\n * a `ComposedText` object, not for use with `DraftEntity.get()`.\n */\nexport type EntityRange = {\n  key: number,\n  offset: number,\n  length: number,\n  ...\n};\n"
  },
  {
    "path": "src/model/encoding/InlineStyleRange.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\n/**\n * A plain object representation of an inline style range.\n */\nexport type InlineStyleRange = {\n  style: string,\n  offset: number,\n  length: number,\n  ...\n};\n"
  },
  {
    "path": "src/model/encoding/RawDraftContentBlock.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {DraftBlockType} from 'DraftBlockType';\nimport type {EntityRange} from 'EntityRange';\nimport type {InlineStyleRange} from 'InlineStyleRange';\n\n/**\n * A plain object representation of a ContentBlock, with all style and entity\n * attribution repackaged as range objects.\n */\nexport type RawDraftContentBlock = {\n  key: ?string,\n  type: DraftBlockType,\n  text: string,\n  depth: ?number,\n  inlineStyleRanges: ?Array<InlineStyleRange>,\n  entityRanges: ?Array<EntityRange>,\n  data?: Object,\n  children?: Array<RawDraftContentBlock>,\n  ...\n};\n"
  },
  {
    "path": "src/model/encoding/RawDraftContentState.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {RawDraftContentBlock} from 'RawDraftContentBlock';\nimport type {RawDraftEntity} from 'RawDraftEntity';\n\n/**\n * A type that represents a composed document as vanilla JavaScript objects,\n * with all styles and entities represented as ranges. Corresponding entity\n * objects are packaged as objects as well.\n *\n * This object is especially useful when sending the document state to the\n * server for storage, as its representation is more concise than our\n * immutable objects.\n */\nexport type RawDraftContentState = {\n  blocks: Array<RawDraftContentBlock>,\n  entityMap: {[key: string]: RawDraftEntity},\n};\n"
  },
  {
    "path": "src/model/encoding/RawDraftEntity.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {DraftEntityMutability} from 'DraftEntityMutability';\nimport type {DraftEntityType} from 'DraftEntityType';\n\n/**\n * A plain object representation of an EntityInstance.\n */\nexport type RawDraftEntity = {\n  type: DraftEntityType,\n  mutability: DraftEntityMutability,\n  data: ?{[key: string]: any, ...},\n  ...\n};\n"
  },
  {
    "path": "src/model/encoding/__tests__/DraftStringKey-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst {stringify, unstringify} = require('DraftStringKey');\n\ntest('must convert maybe strings to a string key', () => {\n  expect(stringify('anything')).toEqual('_anything');\n  expect(stringify(null)).toEqual('_null');\n});\n\ntest('must convert string keys back to a string', () => {\n  expect(unstringify('_anything')).toEqual('anything');\n  // This is a lossy conversion\n  expect(unstringify('_null')).toEqual('null');\n});\n"
  },
  {
    "path": "src/model/encoding/__tests__/__snapshots__/convertFromDraftStateToRaw-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must be able to convert from draft state with ContentBlock to raw 1`] = `\nObject {\n  \"blocks\": Array [\n    Object {\n      \"data\": Object {},\n      \"depth\": 0,\n      \"entityRanges\": Array [],\n      \"inlineStyleRanges\": Array [],\n      \"key\": \"a\",\n      \"text\": \"Alpha\",\n      \"type\": \"unstyled\",\n    },\n    Object {\n      \"data\": Object {},\n      \"depth\": 0,\n      \"entityRanges\": Array [\n        Object {\n          \"key\": 0,\n          \"length\": 5,\n          \"offset\": 0,\n        },\n      ],\n      \"inlineStyleRanges\": Array [\n        Object {\n          \"length\": 5,\n          \"offset\": 0,\n          \"style\": \"BOLD\",\n        },\n      ],\n      \"key\": \"b\",\n      \"text\": \"Bravo\",\n      \"type\": \"unordered-list-item\",\n    },\n    Object {\n      \"data\": Object {},\n      \"depth\": 0,\n      \"entityRanges\": Array [],\n      \"inlineStyleRanges\": Array [],\n      \"key\": \"c\",\n      \"text\": \"Test\",\n      \"type\": \"code-block\",\n    },\n    Object {\n      \"data\": Object {},\n      \"depth\": 0,\n      \"entityRanges\": Array [],\n      \"inlineStyleRanges\": Array [],\n      \"key\": \"d\",\n      \"text\": \"\",\n      \"type\": \"code-block\",\n    },\n    Object {\n      \"data\": Object {},\n      \"depth\": 0,\n      \"entityRanges\": Array [],\n      \"inlineStyleRanges\": Array [],\n      \"key\": \"e\",\n      \"text\": \"\",\n      \"type\": \"code-block\",\n    },\n    Object {\n      \"data\": Object {},\n      \"depth\": 0,\n      \"entityRanges\": Array [],\n      \"inlineStyleRanges\": Array [\n        Object {\n          \"length\": 7,\n          \"offset\": 0,\n          \"style\": \"ITALIC\",\n        },\n      ],\n      \"key\": \"f\",\n      \"text\": \"Charlie\",\n      \"type\": \"blockquote\",\n    },\n  ],\n  \"entityMap\": Object {\n    \"0\": Object {\n      \"data\": Object {},\n      \"mutability\": \"IMMUTABLE\",\n      \"type\": \"IMAGE\",\n    },\n  },\n}\n`;\n\nexports[`must be able to convert from draft state with ContentBlockNode to raw 1`] = `\nObject {\n  \"blocks\": Array [\n    Object {\n      \"children\": Array [\n        Object {\n          \"children\": Array [\n            Object {\n              \"children\": Array [],\n              \"data\": Object {},\n              \"depth\": 0,\n              \"entityRanges\": Array [],\n              \"inlineStyleRanges\": Array [],\n              \"key\": \"C\",\n              \"text\": \"left block\",\n              \"type\": \"unstyled\",\n            },\n            Object {\n              \"children\": Array [],\n              \"data\": Object {},\n              \"depth\": 0,\n              \"entityRanges\": Array [],\n              \"inlineStyleRanges\": Array [],\n              \"key\": \"D\",\n              \"text\": \"right block\",\n              \"type\": \"unstyled\",\n            },\n          ],\n          \"data\": Object {},\n          \"depth\": 0,\n          \"entityRanges\": Array [],\n          \"inlineStyleRanges\": Array [],\n          \"key\": \"B\",\n          \"text\": \"\",\n          \"type\": \"unstyled\",\n        },\n        Object {\n          \"children\": Array [],\n          \"data\": Object {},\n          \"depth\": 0,\n          \"entityRanges\": Array [],\n          \"inlineStyleRanges\": Array [],\n          \"key\": \"E\",\n          \"text\": \"This is a tree based document!\",\n          \"type\": \"header-one\",\n        },\n      ],\n      \"data\": Object {},\n      \"depth\": 0,\n      \"entityRanges\": Array [],\n      \"inlineStyleRanges\": Array [],\n      \"key\": \"A\",\n      \"text\": \"\",\n      \"type\": \"unstyled\",\n    },\n  ],\n  \"entityMap\": Object {},\n}\n`;\n\nexports[`must be able to convert from draft state with noncontiguous entities to raw 1`] = `\nObject {\n  \"blocks\": Array [\n    Object {\n      \"data\": Object {},\n      \"depth\": 0,\n      \"entityRanges\": Array [\n        Object {\n          \"key\": 0,\n          \"length\": 5,\n          \"offset\": 0,\n        },\n        Object {\n          \"key\": 1,\n          \"length\": 5,\n          \"offset\": 6,\n        },\n        Object {\n          \"key\": 2,\n          \"length\": 5,\n          \"offset\": 12,\n        },\n      ],\n      \"inlineStyleRanges\": Array [],\n      \"key\": \"a\",\n      \"text\": \"link2 link2 link3\",\n      \"type\": \"unstyled\",\n    },\n    Object {\n      \"data\": Object {},\n      \"depth\": 0,\n      \"entityRanges\": Array [\n        Object {\n          \"key\": 2,\n          \"length\": 5,\n          \"offset\": 0,\n        },\n        Object {\n          \"key\": 0,\n          \"length\": 5,\n          \"offset\": 6,\n        },\n        Object {\n          \"key\": 3,\n          \"length\": 5,\n          \"offset\": 12,\n        },\n      ],\n      \"inlineStyleRanges\": Array [],\n      \"key\": \"b\",\n      \"text\": \"link4 link2 link5\",\n      \"type\": \"unstyled\",\n    },\n  ],\n  \"entityMap\": Object {\n    \"0\": Object {\n      \"data\": Object {\n        \"url\": \"www.3.com\",\n      },\n      \"mutability\": \"IMMUTABLE\",\n      \"type\": \"LINK\",\n    },\n    \"1\": Object {\n      \"data\": Object {\n        \"url\": \"www.4.com\",\n      },\n      \"mutability\": \"IMMUTABLE\",\n      \"type\": \"LINK\",\n    },\n    \"2\": Object {\n      \"data\": Object {\n        \"url\": \"www.5.com\",\n      },\n      \"mutability\": \"IMMUTABLE\",\n      \"type\": \"LINK\",\n    },\n    \"3\": Object {\n      \"data\": Object {\n        \"url\": \"www.6.com\",\n      },\n      \"mutability\": \"IMMUTABLE\",\n      \"type\": \"LINK\",\n    },\n  },\n}\n`;\n"
  },
  {
    "path": "src/model/encoding/__tests__/__snapshots__/convertFromHTMLToContentBlocks-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`Should *not* import recognised draft li depths when nesting enabled 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": \"key3\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"depth0-0\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"nextSibling\": \"key4\",\n    \"parent\": null,\n    \"prevSibling\": \"key2\",\n    \"text\": \"depth0-1\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"nextSibling\": \"key5\",\n    \"parent\": null,\n    \"prevSibling\": \"key3\",\n    \"text\": \"depth0-2\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key5\",\n    \"nextSibling\": \"key6\",\n    \"parent\": null,\n    \"prevSibling\": \"key4\",\n    \"text\": \"depth0-3\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key6\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key5\",\n    \"text\": \"depth0-4\",\n    \"type\": \"unordered-list-item\",\n  },\n]\n`;\n\nexports[`Should import line breaks without creating a leading space 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"Line 1\n    Line 2\n    Line 3\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`Should import recognised draft li depths when nesting disabled 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"depth0\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 1,\n    \"key\": \"key3\",\n    \"text\": \"depth1\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 2,\n    \"key\": \"key4\",\n    \"text\": \"depth2\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 3,\n    \"key\": \"key5\",\n    \"text\": \"depth3\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 4,\n    \"key\": \"key6\",\n    \"text\": \"depth4\",\n    \"type\": \"unordered-list-item\",\n  },\n]\n`;\n\nexports[`Should import two blockquotes without extra line breaks 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"First\",\n    \"type\": \"blockquote\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Second\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`Should not create empty container blocks around ol and their list items 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"something\",\n    \"type\": \"ordered-list-item\",\n  },\n]\n`;\n\nexports[`Should not create empty container blocks around ol and their list items when nesting enabled 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"something\",\n    \"type\": \"ordered-list-item\",\n  },\n]\n`;\n\nexports[`Should not create empty container blocks around ul and their list items 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"something\",\n    \"type\": \"unordered-list-item\",\n  },\n]\n`;\n\nexports[`Should not create empty container blocks around ul and their list items when nesting enabled 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"something\",\n    \"type\": \"unordered-list-item\",\n  },\n]\n`;\n\nexports[`Should preserve entities for whitespace-only content 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \" before after \",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`Should preserve spacing around inline tags 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Some stylised text\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`Should properly handle nested attribute styles 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"boldnot boldbold again\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`Should recognize preformatted blocks 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"following some pre some_code_stuff\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`Should recognize preformatted blocks mixed other styles 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"CODE\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"example bold and code\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`Should recognized and *not* override html structure when having known draft-js classname with nesting enabled 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": \"key3\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"depth0-0\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 1,\n    \"key\": \"key3\",\n    \"nextSibling\": \"key4\",\n    \"parent\": null,\n    \"prevSibling\": \"key2\",\n    \"text\": \"depth1-0\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 1,\n    \"key\": \"key4\",\n    \"nextSibling\": \"key5\",\n    \"parent\": null,\n    \"prevSibling\": \"key3\",\n    \"text\": \"depth1-1\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key5\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key4\",\n    \"text\": \"depth0-1\",\n    \"type\": \"unordered-list-item\",\n  },\n]\n`;\n\nexports[`Should recognized and override html structure when having known draft-js classname with nesting disabled 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"depth0\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 1,\n    \"key\": \"key3\",\n    \"text\": \"depth1\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 2,\n    \"key\": \"key4\",\n    \"text\": \"depth2\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 3,\n    \"key\": \"key5\",\n    \"text\": \"depth3\",\n    \"type\": \"unordered-list-item\",\n  },\n]\n`;\n\nexports[`Should recognized list deep nesting 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"depth0-0\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"depth0-1\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 1,\n    \"key\": \"key4\",\n    \"text\": \"depth1-0\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 1,\n    \"key\": \"key5\",\n    \"text\": \"depth1-1\",\n    \"type\": \"ordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 2,\n    \"key\": \"key6\",\n    \"text\": \"depth2-0\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 2,\n    \"key\": \"key7\",\n    \"text\": \"depth2-1\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key8\",\n    \"text\": \"depth0-2\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key9\",\n    \"text\": \"depth0-3\",\n    \"type\": \"ordered-list-item\",\n  },\n]\n`;\n\nexports[`Should recognized list deep nesting when nesting enabled 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": \"key3\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"depth0-0\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"nextSibling\": \"key4\",\n    \"parent\": null,\n    \"prevSibling\": \"key2\",\n    \"text\": \"depth0-1\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 1,\n    \"key\": \"key4\",\n    \"nextSibling\": \"key5\",\n    \"parent\": null,\n    \"prevSibling\": \"key3\",\n    \"text\": \"depth1-0\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 1,\n    \"key\": \"key5\",\n    \"nextSibling\": \"key6\",\n    \"parent\": null,\n    \"prevSibling\": \"key4\",\n    \"text\": \"depth1-1\",\n    \"type\": \"ordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 2,\n    \"key\": \"key6\",\n    \"nextSibling\": \"key7\",\n    \"parent\": null,\n    \"prevSibling\": \"key5\",\n    \"text\": \"depth2-0\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 2,\n    \"key\": \"key7\",\n    \"nextSibling\": \"key8\",\n    \"parent\": null,\n    \"prevSibling\": \"key6\",\n    \"text\": \"depth2-1\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key8\",\n    \"nextSibling\": \"key9\",\n    \"parent\": null,\n    \"prevSibling\": \"key7\",\n    \"text\": \"depth0-2\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key9\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key8\",\n    \"text\": \"depth0-3\",\n    \"type\": \"ordered-list-item\",\n  },\n]\n`;\n\nexports[`Should scope attribute styles 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n          \"UNDERLINE\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n          \"UNDERLINE\",\n        ],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"these won't accumulate styles    but this span will\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`converts deeply nested html blocks when experimentalTreeDataSupport is enabled 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": \"key3\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Some quote\",\n    \"type\": \"ordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"key4\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key2\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"key5\",\n      \"key6\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"nextSibling\": null,\n    \"parent\": \"key3\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"blockquote\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key5\",\n    \"nextSibling\": \"key6\",\n    \"parent\": \"key4\",\n    \"prevSibling\": null,\n    \"text\": \"Hello World!\",\n    \"type\": \"header-one\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key6\",\n    \"nextSibling\": null,\n    \"parent\": \"key4\",\n    \"prevSibling\": \"key5\",\n    \"text\": \"lorem ipsum\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`converts nested html blocks when experimentalTreeDataSupport is enabled 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"key3\",\n      \"key4\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"blockquote\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"nextSibling\": \"key4\",\n    \"parent\": \"key2\",\n    \"prevSibling\": null,\n    \"text\": \"Hello World!\",\n    \"type\": \"header-one\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"nextSibling\": null,\n    \"parent\": \"key2\",\n    \"prevSibling\": \"key3\",\n    \"text\": \"lorem ipsum\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`converts text nodes to unstyled elements when leading nested blocks when experimentalTreeDataSupport is enabled 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"key3\",\n      \"key4\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"blockquote\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"nextSibling\": \"key4\",\n    \"parent\": \"key2\",\n    \"prevSibling\": null,\n    \"text\": \"Hello World!\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"nextSibling\": null,\n    \"parent\": \"key2\",\n    \"prevSibling\": \"key3\",\n    \"text\": \"lorem ipsum\",\n    \"type\": \"header-one\",\n  },\n]\n`;\n\nexports[`does not convert deeply nested html blocks when experimentalTreeDataSupport is disabled 1`] = `false`;\n\nexports[`does not convert deeply nested html blocks when experimentalTreeDataSupport is disabled 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"Some quote\",\n    \"type\": \"ordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"Hello World!\nlorem ipsum\",\n    \"type\": \"ordered-list-item\",\n  },\n]\n`;\n\nexports[`eliminates useless blocks when experimentalTreeDataSupport is disabled 1`] = `false`;\n\nexports[`eliminates useless blocks when experimentalTreeDataSupport is disabled 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Hello\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key5\",\n    \"text\": \"World\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`highlighted text should be recognized and considered styled characters 1`] = `\nArray [\n  Immutable.Record {\n    \"key\": \"key2\",\n    \"type\": \"unstyled\",\n    \"text\": \"test\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"HIGHLIGHT\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"HIGHLIGHT\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"HIGHLIGHT\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"HIGHLIGHT\",\n        ],\n        \"entity\": null,\n      },\n    ],\n    \"depth\": 0,\n    \"data\": Immutable.Map {},\n  },\n]\n`;\n\nexports[`img with alt text should have alt text as placeholder 1`] = `\"facebook website\"`;\n\nexports[`img with data protocol should be correctly parsed 1`] = `\"\\\\ud83d\\\\udcf7\"`;\n\nexports[`img with empty alt text should have camera emoji content 1`] = `\"\\\\ud83d\\\\udcf7\"`;\n\nexports[`img with http protocol should have camera emoji content 1`] = `\"\\\\ud83d\\\\udcf7\"`;\n\nexports[`img with https protocol should have camera emoji content 1`] = `\"\\\\ud83d\\\\udcf7\"`;\n\nexports[`line break should be correctly parsed - multiple <br> in a content block 1`] = `\nArray [\n  Immutable.Record {\n    \"key\": \"key2\",\n    \"type\": \"unstyled\",\n    \"text\": \"Hello World! \n \n      lorem ipsum\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"depth\": 0,\n    \"data\": Immutable.Map {},\n  },\n]\n`;\n\nexports[`line break should be correctly parsed - single <br> 1`] = `\nArray [\n  Immutable.Record {\n    \"key\": \"key2\",\n    \"type\": \"unstyled\",\n    \"text\": \"Hello World! \n      lorem ipsum\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [\n          \"BOLD\",\n        ],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"depth\": 0,\n    \"data\": Immutable.Map {},\n  },\n]\n`;\n\nexports[`must convert root ContentBlockNodes to matching ContentBlock nodes for <blockquote /> 1`] = `true`;\n\nexports[`must convert root ContentBlockNodes to matching ContentBlock nodes for <div /> 1`] = `true`;\n\nexports[`must convert root ContentBlockNodes to matching ContentBlock nodes for <figure /> 1`] = `true`;\n\nexports[`must convert root ContentBlockNodes to matching ContentBlock nodes for <h1 /> 1`] = `true`;\n\nexports[`must convert root ContentBlockNodes to matching ContentBlock nodes for <h2 /> 1`] = `true`;\n\nexports[`must convert root ContentBlockNodes to matching ContentBlock nodes for <h3 /> 1`] = `true`;\n\nexports[`must convert root ContentBlockNodes to matching ContentBlock nodes for <h4 /> 1`] = `true`;\n\nexports[`must convert root ContentBlockNodes to matching ContentBlock nodes for <h5 /> 1`] = `true`;\n\nexports[`must convert root ContentBlockNodes to matching ContentBlock nodes for <h6 /> 1`] = `true`;\n\nexports[`must convert root ContentBlockNodes to matching ContentBlock nodes for <li /> 1`] = `true`;\n\nexports[`must convert root ContentBlockNodes to matching ContentBlock nodes for <p /> 1`] = `true`;\n\nexports[`must convert root ContentBlockNodes to matching ContentBlock nodes for <pre /> 1`] = `true`;\n\nexports[`must not merge tags when converting adjacent <blockquote /> 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"a\",\n    \"type\": \"blockquote\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"b\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <blockquote /> 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": \"key3\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"a\",\n    \"type\": \"blockquote\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key2\",\n    \"text\": \"b\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <div /> 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"a\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"b\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <div /> 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": \"key3\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"a\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key2\",\n    \"text\": \"b\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <figure /> 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"a\",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"b\",\n    \"type\": \"atomic\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <figure /> 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": \"key3\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"a\",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key2\",\n    \"text\": \"b\",\n    \"type\": \"atomic\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <h1 /> 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"a\",\n    \"type\": \"header-one\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"b\",\n    \"type\": \"header-one\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <h1 /> 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": \"key3\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"a\",\n    \"type\": \"header-one\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key2\",\n    \"text\": \"b\",\n    \"type\": \"header-one\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <h2 /> 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"a\",\n    \"type\": \"header-two\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"b\",\n    \"type\": \"header-two\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <h2 /> 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": \"key3\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"a\",\n    \"type\": \"header-two\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key2\",\n    \"text\": \"b\",\n    \"type\": \"header-two\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <h3 /> 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"a\",\n    \"type\": \"header-three\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"b\",\n    \"type\": \"header-three\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <h3 /> 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": \"key3\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"a\",\n    \"type\": \"header-three\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key2\",\n    \"text\": \"b\",\n    \"type\": \"header-three\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <h4 /> 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"a\",\n    \"type\": \"header-four\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"b\",\n    \"type\": \"header-four\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <h4 /> 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": \"key3\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"a\",\n    \"type\": \"header-four\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key2\",\n    \"text\": \"b\",\n    \"type\": \"header-four\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <h5 /> 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"a\",\n    \"type\": \"header-five\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"b\",\n    \"type\": \"header-five\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <h5 /> 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": \"key3\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"a\",\n    \"type\": \"header-five\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key2\",\n    \"text\": \"b\",\n    \"type\": \"header-five\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <h6 /> 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"a\",\n    \"type\": \"header-six\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"b\",\n    \"type\": \"header-six\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <h6 /> 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": \"key3\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"a\",\n    \"type\": \"header-six\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key2\",\n    \"text\": \"b\",\n    \"type\": \"header-six\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <li /> 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"a\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"b\",\n    \"type\": \"unordered-list-item\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <li /> 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": \"key3\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"a\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key2\",\n    \"text\": \"b\",\n    \"type\": \"unordered-list-item\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <p /> 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"a\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"b\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <p /> 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": \"key3\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"a\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key2\",\n    \"text\": \"b\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <pre /> 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"a\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"b\",\n    \"type\": \"code-block\",\n  },\n]\n`;\n\nexports[`must not merge tags when converting adjacent <pre /> 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": \"key3\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"a\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key2\",\n    \"text\": \"b\",\n    \"type\": \"code-block\",\n  },\n]\n`;\n"
  },
  {
    "path": "src/model/encoding/__tests__/__snapshots__/convertFromRawToDraftState-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`convert from raw tree draft content state 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"B\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"D\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"A\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"D\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"left block\",\n    \"type\": \"unstyled\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"right block\",\n    \"type\": \"unstyled\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"A\",\n    \"prevSibling\": \"B\",\n    \"text\": \"This is a tree based document!\",\n    \"type\": \"header-one\",\n  },\n}\n`;\n\nexports[`ignore empty children array 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"A\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"C\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"B\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"C\",\n    \"type\": \"ordered-list-item\",\n  },\n}\n`;\n\nexports[`ignore empty children array for tree conversion 1 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"A\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"C\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"B\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"C\",\n    \"type\": \"ordered-list-item\",\n  },\n}\n`;\n\nexports[`ignore empty children array for tree conversion 2 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"A\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"C\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"B\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"C\",\n    \"type\": \"ordered-list-item\",\n  },\n}\n`;\n\nexports[`must be able to convert content blocks that have list with depth from raw state to tree state when experimentalTreeDataSupport is enabled 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"key1\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 1,\n    \"key\": \"B\",\n    \"nextSibling\": \"key2\",\n    \"parent\": \"key1\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 2,\n    \"key\": \"C\",\n    \"nextSibling\": null,\n    \"parent\": \"key2\",\n    \"prevSibling\": null,\n    \"text\": \"deeply nested list\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"key1\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"B\",\n      \"key2\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key1\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"key2\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n    ],\n    \"data\": Object {},\n    \"depth\": 1,\n    \"key\": \"key2\",\n    \"nextSibling\": null,\n    \"parent\": \"key1\",\n    \"prevSibling\": \"B\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n}\n`;\n\nexports[`must be able to convert from raw state to tree state when experimentalTreeDataSupport is enabled 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"AAAA\",\n    \"type\": \"unstyled\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"C\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"BBBB\",\n    \"type\": \"unstyled\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"CCCC\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`must be able to convert from styled blocks and entities mapped raw state 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must convert from raw tree draft to raw content state when experimentalTreeDataSupport is disabled 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"left block\",\n    \"type\": \"unstyled\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"text\": \"right block\",\n    \"type\": \"unstyled\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"text\": \"This is a tree based document!\",\n    \"type\": \"header-one\",\n  },\n}\n`;\n\nexports[`must map falsey block types to default value of unstyled 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"AAAA\",\n    \"type\": \"unstyled\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"BBBB\",\n    \"type\": \"unstyled\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"CCCC\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n"
  },
  {
    "path": "src/model/encoding/__tests__/__snapshots__/decodeEntityRanges-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must decode when an entity is present 1`] = `\nArray [\n  null,\n  null,\n  6,\n  6,\n  null,\n]\n`;\n\nexports[`must decode when an entity is present more than once 1`] = `\nArray [\n  null,\n  null,\n  6,\n  6,\n  null,\n  6,\n  6,\n  null,\n]\n`;\n\nexports[`must decode when multiple entities present 1`] = `\nArray [\n  null,\n  null,\n  6,\n  6,\n  null,\n  8,\n  8,\n  null,\n]\n`;\n\nexports[`must decode when no entities present 1`] = `\nArray [\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n]\n`;\n\nexports[`must handle ranges that include surrogate pairs 1`] = `\nArray [\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  6,\n  6,\n  6,\n  6,\n  6,\n  6,\n  null,\n  null,\n  8,\n  8,\n  null,\n]\n`;\n"
  },
  {
    "path": "src/model/encoding/__tests__/__snapshots__/decodeInlineStyleRanges-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must decode for a flat styled block 1`] = `\nArray [\n  Array [\n    \"BOLD\",\n  ],\n  Array [\n    \"BOLD\",\n  ],\n  Array [\n    \"BOLD\",\n  ],\n  Array [\n    \"BOLD\",\n  ],\n  Array [\n    \"BOLD\",\n  ],\n]\n`;\n\nexports[`must decode for a mixed-style block 1`] = `\nArray [\n  Array [\n    \"BOLD\",\n    \"UNDERLINE\",\n  ],\n  Array [\n    \"BOLD\",\n    \"ITALIC\",\n    \"UNDERLINE\",\n  ],\n  Array [\n    \"BOLD\",\n    \"ITALIC\",\n  ],\n  Array [\n    \"ITALIC\",\n  ],\n  Array [\n    \"BOLD\",\n  ],\n]\n`;\n\nexports[`must decode for an unstyled block 1`] = `\nArray [\n  Array [],\n  Array [],\n  Array [],\n  Array [],\n  Array [],\n]\n`;\n\nexports[`must decode for strings that contain surrogate pairs in UTF-16 1`] = `\nArray [\n  Array [],\n  Array [],\n  Array [],\n  Array [],\n  Array [\n    \"BOLD\",\n  ],\n  Array [\n    \"BOLD\",\n  ],\n  Array [\n    \"BOLD\",\n    \"ITALIC\",\n  ],\n  Array [\n    \"BOLD\",\n    \"ITALIC\",\n  ],\n  Array [\n    \"BOLD\",\n    \"ITALIC\",\n  ],\n  Array [\n    \"ITALIC\",\n  ],\n  Array [\n    \"ITALIC\",\n  ],\n  Array [\n    \"ITALIC\",\n  ],\n  Array [\n    \"ITALIC\",\n  ],\n  Array [\n    \"ITALIC\",\n  ],\n  Array [\n    \"ITALIC\",\n  ],\n  Array [],\n  Array [],\n]\n`;\n"
  },
  {
    "path": "src/model/encoding/__tests__/__snapshots__/encodeEntityRanges-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must handle ranges that include surrogate pairs 1`] = `\nArray [\n  Object {\n    \"key\": 0,\n    \"length\": 5,\n    \"offset\": 6,\n  },\n  Object {\n    \"key\": 1,\n    \"length\": 2,\n    \"offset\": 13,\n  },\n]\n`;\n\nexports[`must return an empty array if no entities present 1`] = `Array []`;\n\nexports[`must return an empty array if no entities present 2`] = `Array []`;\n\nexports[`must return ranges with an entity present more than once 1`] = `\nArray [\n  Object {\n    \"key\": 0,\n    \"length\": 2,\n    \"offset\": 2,\n  },\n  Object {\n    \"key\": 0,\n    \"length\": 2,\n    \"offset\": 5,\n  },\n]\n`;\n\nexports[`must return ranges with multiple entities present 1`] = `\nArray [\n  Object {\n    \"key\": 0,\n    \"length\": 2,\n    \"offset\": 2,\n  },\n  Object {\n    \"key\": 1,\n    \"length\": 2,\n    \"offset\": 5,\n  },\n]\n`;\n\nexports[`must return ranges with the storage-mapped key 1`] = `\nArray [\n  Object {\n    \"key\": 0,\n    \"length\": 2,\n    \"offset\": 2,\n  },\n]\n`;\n"
  },
  {
    "path": "src/model/encoding/__tests__/__snapshots__/encodeInlineStyleRanges-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must encode custom styles 1`] = `\nArray [\n  Object {\n    \"length\": 4,\n    \"offset\": 0,\n    \"style\": \"foo\",\n  },\n  Object {\n    \"length\": 2,\n    \"offset\": 2,\n    \"style\": \"bar\",\n  },\n  Object {\n    \"length\": 2,\n    \"offset\": 4,\n    \"style\": \"BOLD\",\n  },\n]\n`;\n\nexports[`must encode for a complex styled document 1`] = `\nArray [\n  Object {\n    \"length\": 4,\n    \"offset\": 0,\n    \"style\": \"BOLD\",\n  },\n  Object {\n    \"length\": 2,\n    \"offset\": 5,\n    \"style\": \"BOLD\",\n  },\n  Object {\n    \"length\": 2,\n    \"offset\": 8,\n    \"style\": \"BOLD\",\n  },\n  Object {\n    \"length\": 3,\n    \"offset\": 5,\n    \"style\": \"ITALIC\",\n  },\n  Object {\n    \"length\": 1,\n    \"offset\": 9,\n    \"style\": \"ITALIC\",\n  },\n  Object {\n    \"length\": 3,\n    \"offset\": 7,\n    \"style\": \"UNDERLINE\",\n  },\n]\n`;\n\nexports[`must encode for a flat styled document 1`] = `\nArray [\n  Object {\n    \"length\": 20,\n    \"offset\": 0,\n    \"style\": \"BOLD\",\n  },\n]\n`;\n\nexports[`must encode for a flat styled document 2`] = `\nArray [\n  Object {\n    \"length\": 20,\n    \"offset\": 0,\n    \"style\": \"BOLD\",\n  },\n  Object {\n    \"length\": 20,\n    \"offset\": 0,\n    \"style\": \"ITALIC\",\n  },\n]\n`;\n\nexports[`must encode for a flat styled document 3`] = `\nArray [\n  Object {\n    \"length\": 20,\n    \"offset\": 0,\n    \"style\": \"BOLD\",\n  },\n  Object {\n    \"length\": 20,\n    \"offset\": 0,\n    \"style\": \"ITALIC\",\n  },\n  Object {\n    \"length\": 20,\n    \"offset\": 0,\n    \"style\": \"UNDERLINE\",\n  },\n]\n`;\n\nexports[`must encode for an unstyled document 1`] = `Array []`;\n\nexports[`must encode for an unstyled document 2`] = `Array []`;\n\nexports[`must encode for an unstyled document 3`] = `Array []`;\n\nexports[`must encode for an unstyled document 4`] = `Array []`;\n\nexports[`must encode for strings with surrogate pairs 1`] = `\nArray [\n  Object {\n    \"length\": 4,\n    \"offset\": 4,\n    \"style\": \"BOLD\",\n  },\n  Object {\n    \"length\": 8,\n    \"offset\": 6,\n    \"style\": \"ITALIC\",\n  },\n]\n`;\n"
  },
  {
    "path": "src/model/encoding/__tests__/__snapshots__/sanitizeDraftText-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must strip all carriage returns 1`] = `\"test\"`;\n\nexports[`must strip leading carriage returns 1`] = `\"test\"`;\n\nexports[`must strip trailing carriage returns 1`] = `\"test\"`;\n\nexports[`must strip two trailing carriage returns 1`] = `\"test\"`;\n\nexports[`must strip within carriage returns 1`] = `\"test\"`;\n"
  },
  {
    "path": "src/model/encoding/__tests__/convertFromDraftStateToRaw-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst BlockMapBuilder = require('BlockMapBuilder');\nconst CharacterMetadata = require('CharacterMetadata');\nconst ContentBlock = require('ContentBlock');\nconst ContentBlockNode = require('ContentBlockNode');\nconst ContentState = require('ContentState');\nconst DraftEntityInstance = require('DraftEntityInstance');\n\nconst convertFromDraftStateToRaw = require('convertFromDraftStateToRaw');\nconst getSampleStateForTesting = require('getSampleStateForTesting');\nconst Immutable = require('immutable');\nconst mockUUID = require('mockUUID');\n\njest.mock('uuid', () => jest.fn(mockUUID));\n\nconst {contentState} = getSampleStateForTesting();\n\nconst treeContentState = contentState.setBlockMap(\n  BlockMapBuilder.createFromArray([\n    new ContentBlockNode({\n      key: 'A',\n      children: Immutable.List.of('B', 'E'),\n    }),\n    new ContentBlockNode({\n      parent: 'A',\n      key: 'B',\n      nextSibling: 'C',\n      children: Immutable.List.of('C', 'D'),\n    }),\n    new ContentBlockNode({\n      parent: 'B',\n      key: 'C',\n      text: 'left block',\n      nextSibling: 'D',\n    }),\n    new ContentBlockNode({\n      parent: 'B',\n      key: 'D',\n      text: 'right block',\n      prevSibling: 'C',\n    }),\n    new ContentBlockNode({\n      parent: 'A',\n      key: 'E',\n      text: 'This is a tree based document!',\n      type: 'header-one',\n      prevSibling: 'B',\n    }),\n  ]),\n);\n\nconst getMetadata = (\n  entityKey:\n    | $TEMPORARY$string<'3'>\n    | $TEMPORARY$string<'4'>\n    | $TEMPORARY$string<'5'>\n    | $TEMPORARY$string<'6'>,\n) => Immutable.Repeat(CharacterMetadata.create({entity: entityKey}), 5);\nconst getLink = (\n  entityKey:\n    | $TEMPORARY$string<'3'>\n    | $TEMPORARY$string<'4'>\n    | $TEMPORARY$string<'5'>\n    | $TEMPORARY$string<'6'>,\n) =>\n  new DraftEntityInstance({\n    type: 'LINK',\n    mutabiltity: 'MUTABLE',\n    data: {\n      url: `www.${entityKey}.com`,\n    },\n  });\n// We start numbering our entities with '3' because getSampleStateForTesting\n// already created an entity with key '2'.\nconst contentStateWithNonContiguousEntities = ContentState.createFromBlockArray(\n  [\n    new ContentBlock({\n      key: 'a',\n      type: 'unstyled',\n      text: 'link2 link2 link3',\n      characterList: getMetadata('3')\n        .toList()\n        .push(CharacterMetadata.EMPTY)\n        .concat(getMetadata('4'))\n        .push(CharacterMetadata.EMPTY)\n        .concat(getMetadata('5')),\n    }),\n    new ContentBlock({\n      key: 'b',\n      type: 'unstyled',\n      text: 'link4 link2 link5',\n      characterList: getMetadata('5')\n        .toList()\n        .push(CharacterMetadata.EMPTY)\n        .concat(getMetadata('3'))\n        .push(CharacterMetadata.EMPTY)\n        .concat(getMetadata('6')),\n    }),\n  ],\n)\n  .addEntity(getLink('3'))\n  .addEntity(getLink('4'))\n  .addEntity(getLink('5'))\n  .addEntity(getLink('6'));\n\nconst assertConvertFromDraftStateToRaw = (content: ContentState) => {\n  expect(convertFromDraftStateToRaw(content)).toMatchSnapshot();\n};\n\ntest('must be able to convert from draft state with ContentBlock to raw', () => {\n  assertConvertFromDraftStateToRaw(contentState);\n});\n\ntest('must be able to convert from draft state with ContentBlockNode to raw', () => {\n  assertConvertFromDraftStateToRaw(treeContentState);\n});\n\ntest('must be able to convert from draft state with noncontiguous entities to raw', () => {\n  assertConvertFromDraftStateToRaw(contentStateWithNonContiguousEntities);\n});\n"
  },
  {
    "path": "src/model/encoding/__tests__/convertFromHTMLToContentBlocks-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nexpect.addSnapshotSerializer(require('NonASCIIStringSnapshotSerializer'));\n\njest.mock('generateRandomKey');\n\nconst DefaultDraftBlockRenderMap = require('DefaultDraftBlockRenderMap');\n\nconst convertFromHTMLToContentBlocks = require('convertFromHTMLToContentBlocks');\nconst cx = require('cx');\nconst getSafeBodyFromHTML = require('getSafeBodyFromHTML');\nconst mockUUID = require('mockUUID');\n\nconst DEFAULT_CONFIG = {\n  DOMBuilder: getSafeBodyFromHTML,\n  blockRenderMap: DefaultDraftBlockRenderMap,\n  experimentalTreeDataSupport: false,\n};\n\nconst IMAGE_DATA_URL =\n  'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///' +\n  'yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';\n\nconst SUPPORTED_TAGS = [\n  'blockquote',\n  'div',\n  'figure',\n  'h1',\n  'h2',\n  'h3',\n  'h4',\n  'h5',\n  'h6',\n  'li',\n  'p',\n  'pre',\n];\n\nconst normalizeBlock = (block: $FlowFixMe) => {\n  const {type, depth, text, characterList} = block;\n\n  return {\n    type,\n    depth,\n    text,\n    characterList,\n  };\n};\n\nconst toggleExperimentalTreeDataSupport = (enabled: $FlowFixMe) => {\n  jest.doMock('gkx', () => name => {\n    if (name === 'draftjs_paste_emojis') {\n      return true;\n    }\n    if (name === 'draft_tree_data_support') {\n      return enabled;\n    }\n    return false;\n  });\n};\n\nbeforeEach(() => {\n  jest.resetModules();\n  jest.mock('uuid', () => mockUUID);\n});\n\nconst convertFromHTML = (\n  html_string: string | $TEMPORARY$string<'a\\n'>,\n  config:\n    | void\n    | $TEMPORARY$object<{...}>\n    | $TEMPORARY$object<{experimentalTreeDataSupport: boolean}>\n    | $TEMPORARY$object<{experimentalTreeDataSupport: boolean, ...}>,\n) => {\n  const options = {\n    ...DEFAULT_CONFIG,\n    ...config,\n  };\n\n  const {DOMBuilder, blockRenderMap, experimentalTreeDataSupport} = options;\n\n  jest.resetModules();\n  toggleExperimentalTreeDataSupport(experimentalTreeDataSupport);\n  return convertFromHTMLToContentBlocks(\n    html_string,\n    DOMBuilder,\n    blockRenderMap,\n  );\n};\n\nconst AreTreeBlockNodesEquivalent = (\n  html_string: string,\n  config: $TEMPORARY$object<{...}> = {},\n) => {\n  const treeEnabled = (\n    convertFromHTML(html_string, {\n      ...config,\n      experimentalTreeDataSupport: true,\n    })?.contentBlocks || []\n  ).map(block => normalizeBlock(block.toJS()));\n\n  const treeDisabled = (\n    convertFromHTML(html_string, {\n      ...config,\n      experimentalTreeDataSupport: false,\n    })?.contentBlocks || []\n  ).map(block => normalizeBlock(block.toJS()));\n\n  return JSON.stringify(treeEnabled) === JSON.stringify(treeDisabled);\n};\n\nconst assertConvertFromHTMLToContentBlocks = (\n  html_string: string,\n  config:\n    | $TEMPORARY$object<{...}>\n    | $TEMPORARY$object<{experimentalTreeDataSupport: boolean}> = {},\n) => {\n  expect(\n    (convertFromHTML(html_string, config)?.contentBlocks || []).map(block =>\n      block.toJS(),\n    ),\n  ).toMatchSnapshot();\n};\n\nconst testConvertingAdjacentHtmlElementsToContentBlocks = (\n  tag: string,\n  experimentalTreeDataSupport?: boolean = false,\n) => {\n  test(`must not merge tags when converting adjacent <${tag} />`, () => {\n    const html_string = `\n      <${tag}>a</${tag}>\n      <${tag}>b</${tag}>\n    `;\n\n    assertConvertFromHTMLToContentBlocks(html_string, {\n      experimentalTreeDataSupport,\n    });\n  });\n};\n\nconst testConvertingHtmlElementsToContentBlocksAndRootContentBlockNodesMatch = (\n  tag: string,\n) => {\n  test(`must convert root ContentBlockNodes to matching ContentBlock nodes for <${tag} />`, () => {\n    expect(\n      AreTreeBlockNodesEquivalent(`<${tag}>a</${tag}> `),\n    ).toMatchSnapshot();\n  });\n};\n\nSUPPORTED_TAGS.forEach(tag =>\n  testConvertingAdjacentHtmlElementsToContentBlocks(tag),\n);\n\ntest('img with http protocol should have camera emoji content', () => {\n  const blocks = convertFromHTMLToContentBlocks(\n    '<img src=\"http://www.facebook.com\">',\n  );\n  expect(blocks?.contentBlocks?.[0].text).toMatchSnapshot();\n  const entityMap = blocks?.entityMap;\n  expect(entityMap).not.toBe(null);\n  if (entityMap != null) {\n    expect(entityMap.last().mutability).toBe('IMMUTABLE');\n  }\n});\n\ntest('img with https protocol should have camera emoji content', () => {\n  const blocks = convertFromHTMLToContentBlocks(\n    '<img src=\"https://www.facebook.com\">',\n  );\n  expect(blocks?.contentBlocks?.[0].text).toMatchSnapshot();\n  const entityMap = blocks?.entityMap;\n  expect(entityMap).not.toBe(null);\n  if (entityMap != null) {\n    expect(entityMap.last().mutability).toBe('IMMUTABLE');\n  }\n});\n\ntest('img with alt text should have alt text as placeholder', () => {\n  const blocks = convertFromHTMLToContentBlocks(\n    '<img alt=\"facebook website\" src=\"https://www.facebook.com\">',\n  );\n  expect(blocks?.contentBlocks?.[0].text).toMatchSnapshot();\n  const entityMap = blocks?.entityMap;\n  expect(entityMap).not.toBe(null);\n  if (entityMap != null) {\n    expect(entityMap.last().mutability).toBe('IMMUTABLE');\n  }\n});\n\ntest('img with empty alt text should have camera emoji content', () => {\n  const blocks = convertFromHTMLToContentBlocks(\n    '<img alt=\"\" src=\"https://www.facebook.com\">',\n  );\n  expect(blocks?.contentBlocks?.[0].text).toMatchSnapshot();\n  const entityMap = blocks?.entityMap;\n  expect(entityMap).not.toBe(null);\n  if (entityMap != null) {\n    expect(entityMap.last().mutability).toBe('IMMUTABLE');\n  }\n});\n\ntest('img with data protocol should be correctly parsed', () => {\n  const blocks = convertFromHTMLToContentBlocks(\n    `<img src=\"${IMAGE_DATA_URL}\">`,\n  );\n  expect(blocks?.contentBlocks?.[0].text).toMatchSnapshot();\n});\n\ntest('line break should be correctly parsed - single <br>', () => {\n  const blocks = convertFromHTMLToContentBlocks(\n    `<div>\n      <b>Hello World!</b>\n      <br />\n      lorem ipsum\n    </div>`,\n  );\n  expect(blocks?.contentBlocks).toMatchSnapshot();\n});\n\ntest('line break should be correctly parsed - multiple <br> in a content block', () => {\n  const blocks = convertFromHTMLToContentBlocks(\n    `<div>\n      <b>Hello World!</b>\n      <br />\n      <br />\n      lorem ipsum\n    </div>`,\n  );\n  expect(blocks?.contentBlocks).toMatchSnapshot();\n});\n\ntest('highlighted text should be recognized and considered styled characters', () => {\n  const blocks = convertFromHTMLToContentBlocks(`<mark>test</mark>`);\n  expect(blocks?.contentBlocks).toMatchSnapshot();\n});\n\ntest('converts nested html blocks when experimentalTreeDataSupport is enabled', () => {\n  const html_string = `\n    <blockquote>\n      <h1>Hello World!</h1>\n      <p>lorem ipsum</p>\n    </blockquote>\n  `;\n\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: true,\n  });\n});\n\ntest('converts text nodes to unstyled elements when leading nested blocks when experimentalTreeDataSupport is enabled', () => {\n  const html_string = `\n    <blockquote>\n      Hello World!\n      <h1>lorem ipsum</h1>\n    </blockquote>\n  `;\n\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: true,\n  });\n});\n\ntest('converts deeply nested html blocks when experimentalTreeDataSupport is enabled', () => {\n  const html_string = `\n    <ol>\n      <li>Some quote</li>\n      <li>\n        <blockquote>\n          <h1>Hello World!</h1>\n          <p>lorem ipsum</p>\n        </blockquote>\n      </li>\n    </ol>\n  `;\n\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: true,\n  });\n});\n\ntest('does not convert deeply nested html blocks when experimentalTreeDataSupport is disabled', () => {\n  const html_string = `\n    <ol>\n      <li>Some quote</li>\n      <li>\n        <blockquote>\n          <h1>Hello World!</h1>\n          <p>lorem ipsum</p>\n        </blockquote>\n      </li>\n    </ol>\n  `;\n\n  expect(AreTreeBlockNodesEquivalent(html_string)).toMatchSnapshot();\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: false,\n  });\n});\n\ntest('eliminates useless blocks when experimentalTreeDataSupport is disabled', () => {\n  const html_string = `\n    <div>\n      <div>\n        <div>Hello</div>\n      </div>\n      <div>World</div>\n    </div>\n  `;\n\n  expect(AreTreeBlockNodesEquivalent(html_string)).toMatchSnapshot();\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: false,\n  });\n});\n\nSUPPORTED_TAGS.forEach(tag =>\n  testConvertingAdjacentHtmlElementsToContentBlocks(tag, true),\n);\n\n// assert that using tree blocks and root content block nodes are equivalent\nSUPPORTED_TAGS.forEach(tag =>\n  testConvertingHtmlElementsToContentBlocksAndRootContentBlockNodesMatch(tag),\n);\n\ntest('Should not create empty container blocks around ul and their list items', () => {\n  const html_string = `\n    <ul>\n      <li>something</li>\n    </ul>\n  `;\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: false,\n  });\n});\n\ntest('Should not create empty container blocks around ul and their list items when nesting enabled', () => {\n  const html_string = `\n    <ul>\n      <li>something</li>\n    </ul>\n  `;\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: true,\n  });\n});\n\ntest('Should not create empty container blocks around ol and their list items', () => {\n  const html_string = `\n    <ol>\n      <li>something</li>\n    </ol>\n  `;\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: false,\n  });\n});\n\ntest('Should not create empty container blocks around ol and their list items when nesting enabled', () => {\n  const html_string = `\n    <ol>\n      <li>something</li>\n    </ol>\n  `;\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: true,\n  });\n});\n\n// Regression test for issue https://github.com/facebook/draft-js/issues/1822\ntest('Should convert heading block after converting new line string', () => {\n  // Convert an HTML string containing a newline\n  // This was previously altering the module's internal state\n  convertFromHTML('a\\n');\n  // Convert again, and assert this is not affected by the previous conversion\n  const contentBlocks = convertFromHTML('<h1>heading</h1>')?.contentBlocks;\n  expect(contentBlocks?.length).toBe(1);\n  const contentBlock = contentBlocks?.[0];\n  // #FIXME: Flow does not yet support method or property calls in optional chains.\n  if (contentBlock != null) {\n    expect(contentBlock.getType()).toBe('header-one');\n    expect(contentBlock.getText()).toBe('heading');\n  }\n});\n\ntest('Should preserve entities for whitespace-only content', () => {\n  const html_string = `\n    <a href=\"http://www.facebook.com\">\n      <b>before</b> <b>after</b>\n    </a>\n  `;\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: false,\n  });\n});\n\ntest('Should import recognised draft li depths when nesting disabled', () => {\n  const html_string = `\n    <ul>\n      <li class=\"${cx('public/DraftStyleDefault/depth0')}\">depth0</li>\n      <li class=\"${cx('public/DraftStyleDefault/depth1')}\">depth1</li>\n      <li class=\"${cx('public/DraftStyleDefault/depth2')}\">depth2</li>\n      <li class=\"${cx('public/DraftStyleDefault/depth3')}\">depth3</li>\n      <li class=\"${cx('public/DraftStyleDefault/depth4')}\">depth4</li>\n    </ul>\n  `;\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: false,\n  });\n});\n\ntest('Should *not* import recognised draft li depths when nesting enabled', () => {\n  const html_string = `\n    <ul>\n      <li class=\"${cx('public/DraftStyleDefault/depth0')}\">depth0-0</li>\n      <li class=\"${cx('public/DraftStyleDefault/depth1')}\">depth0-1</li>\n      <li class=\"${cx('public/DraftStyleDefault/depth2')}\">depth0-2</li>\n      <li class=\"${cx('public/DraftStyleDefault/depth3')}\">depth0-3</li>\n      <li class=\"${cx('public/DraftStyleDefault/depth4')}\">depth0-4</li>\n    </ul>\n  `;\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: true,\n  });\n});\n\ntest('Should preserve spacing around inline tags', () => {\n  const html_string = `\n    <span>Some<span> </span></span><i>stylised</i><span><span> </span></span><b>text</b>\n  `;\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: true,\n  });\n});\n\ntest('Should scope attribute styles', () => {\n  const html_string = `\n    <span style=\"font-weight: 700\">these</span>\n    <span style=\"font-style: italic\">won't</span>\n    <span style=\"text-decoration: underline\">accumulate styles</span>\n    <span style=\"font-weight: 700\">\n      <span style=\"font-style: italic\">\n        <span style=\"text-decoration: underline\">\n          <span>but this span will</span>\n        </span>\n      </span>\n    </span>\n  `;\n\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: true,\n  });\n});\n\ntest('Should properly handle nested attribute styles', () => {\n  const html_string = [\n    '<span style=\"font-weight: bold\">',\n    '<span>bold</span>',\n    '<span style=\"font-weight: normal\">not bold</span>',\n    '<span>bold again</span>',\n    '</span>',\n  ].join('');\n\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: false,\n  });\n});\n\ntest('Should recognized list deep nesting', () => {\n  const html_string = `\n    <ul>\n      <li>depth0-0</li>\n      <li>depth0-1</li>\n      <ul>\n        <li>depth1-0</li>\n      </ul>\n      <ol>\n        <li>depth1-1</li>\n        <ul>\n          <li>depth2-0</li>\n          <li>depth2-1</li>\n        </ul>\n      </ol>\n      <li>depth0-2</li>\n    </ul>\n    <ol>\n      <li>depth0-3</li>\n    </ol>\n  `;\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: false,\n  });\n});\n\ntest('Should recognized list deep nesting when nesting enabled', () => {\n  const html_string = `\n    <ul>\n      <li>depth0-0</li>\n      <li>depth0-1</li>\n      <ul>\n        <li>depth1-0</li>\n      </ul>\n      <ol>\n        <li>depth1-1</li>\n        <ul>\n          <li>depth2-0</li>\n          <li>depth2-1</li>\n        </ul>\n      </ol>\n      <li>depth0-2</li>\n    </ul>\n    <ol>\n      <li>depth0-3</li>\n    </ol>\n  `;\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: true,\n  });\n});\n\ntest('Should recognized and override html structure when having known draft-js classname with nesting disabled', () => {\n  const html_string = `\n    <ul>\n      <li class=\"${cx('public/DraftStyleDefault/depth0')}\">depth0</li>\n      <ul>\n        <li class=\"${cx('public/DraftStyleDefault/depth1')}\">depth1</li>\n        <li class=\"${cx('public/DraftStyleDefault/depth2')}\">depth2</li>\n      </ul>\n      <li class=\"${cx('public/DraftStyleDefault/depth3')}\">depth3</li>\n    </ul>\n  `;\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: false,\n  });\n});\n\ntest('Should recognized and *not* override html structure when having known draft-js classname with nesting enabled', () => {\n  const html_string = `\n    <ul>\n      <li class=\"${cx('public/DraftStyleDefault/depth0')}\">depth0-0</li>\n      <ul>\n        <li class=\"${cx('public/DraftStyleDefault/depth1')}\">depth1-0</li>\n        <li class=\"${cx('public/DraftStyleDefault/depth2')}\">depth1-1</li>\n      </ul>\n      <li class=\"${cx('public/DraftStyleDefault/depth3')}\">depth0-1</li>\n    </ul>\n  `;\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: true,\n  });\n});\n\ntest('Should import line breaks without creating a leading space', () => {\n  const html_string = `\n    Line 1<br/>\n    Line 2<br/>\n    Line 3\n  `;\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: false,\n  });\n});\n\ntest('Should import two blockquotes without extra line breaks', () => {\n  const html_string = `\n    <blockquote>\n      <div>\n        <span>First</span>\n      </div>\n    </blockquote\n    <blockquote>\n      <div>\n        <span>Second</span>\n      </div>\n    </blockquote>\n  `;\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: false,\n  });\n});\n\ntest('Should recognize preformatted blocks', () => {\n  const html_string = `\n    <meta charset='utf-8'><span style=\"font-family: system-ui, -apple-system, system-ui, &quot;.SFNSText-Regular&quot;, sans-serif; font-variant-ligatures: normal; white-space: pre-wrap; display: inline !important;\">following some pre </span><span style=\"font-family: Menlo, Consolas, Monaco, monospace; white-space: pre-line;\">some_code_stuff</span>\n  `;\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: false,\n  });\n});\n\ntest('Should recognize preformatted blocks mixed other styles', () => {\n  const html_string = `\n    <meta charset='utf-8'><span style=\"font-family: system-ui, -apple-system, system-ui, &quot;.SFNSText-Regular&quot;, sans-serif; font-size: 14px; font-weight: 400; white-space: pre-wrap; display: inline !important;\">example </span><span style=\"font-weight: 600; font-family: Menlo, Consolas, Monaco, monospace; white-space: pre-line;\">bold</span><span style=\"font-family: Menlo, Consolas, Monaco, monospace; white-space: pre-line; font-weight: 400;\"> and code</span>\n  `;\n  assertConvertFromHTMLToContentBlocks(html_string, {\n    experimentalTreeDataSupport: false,\n  });\n});\n"
  },
  {
    "path": "src/model/encoding/__tests__/convertFromRawToDraftState-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {EntityRange} from 'EntityRange';\nimport type {InlineStyleRange} from 'InlineStyleRange';\nimport type {RawDraftContentBlock} from 'RawDraftContentBlock';\nimport type {RawDraftContentState} from 'RawDraftContentState';\n\nconst convertFromRawToDraftState = require('convertFromRawToDraftState');\nconst mockUUID = require('mockUUID');\n\njest.mock('generateRandomKey');\n\nconst toggleExperimentalTreeDataSupport = (enabled: boolean) => {\n  jest.doMock('gkx', () => name => {\n    return name === 'draft_tree_data_support' ? enabled : false;\n  });\n};\n\nconst assertDraftState = (rawState: RawDraftContentState) => {\n  expect(\n    convertFromRawToDraftState(rawState).getBlockMap().toJS(),\n  ).toMatchSnapshot();\n};\n\nbeforeEach(() => {\n  jest.resetModules();\n  jest.mock('uuid', () => mockUUID);\n});\n\ntest('must map falsey block types to default value of unstyled', () => {\n  const rawState = {\n    blocks: [\n      {\n        key: 'A',\n        text: 'AAAA',\n        depth: 0,\n        entityRanges: ([]: Array<EntityRange>),\n        inlineStyleRanges: ([]: Array<InlineStyleRange>),\n      },\n      {\n        key: 'B',\n        text: 'BBBB',\n        type: null,\n        depth: 0,\n        entityRanges: ([]: Array<EntityRange>),\n        inlineStyleRanges: ([]: Array<InlineStyleRange>),\n      },\n      {\n        key: 'C',\n        text: 'CCCC',\n        type: undefined,\n        depth: 0,\n        entityRanges: ([]: Array<EntityRange>),\n        inlineStyleRanges: ([]: Array<InlineStyleRange>),\n      },\n    ],\n    entityMap: {},\n  };\n\n  // $FlowFixMe looks like the whole point of the test is to verify something prevented by flow? Let it be for now.\n  assertDraftState(rawState);\n});\n\ntest('must be able to convert from styled blocks and entities mapped raw state', () => {\n  const rawState = {\n    blocks: [\n      {\n        data: {},\n        depth: 0,\n        entityRanges: ([]: Array<EntityRange>),\n        inlineStyleRanges: ([]: Array<InlineStyleRange>),\n        key: 'a',\n        text: 'Alpha',\n        type: 'unstyled',\n      },\n      {\n        data: {},\n        depth: 0,\n        entityRanges: [\n          {\n            key: 0,\n            length: 5,\n            offset: 0,\n          },\n        ],\n        inlineStyleRanges: [\n          {\n            length: 5,\n            offset: 0,\n            style: 'BOLD',\n          },\n        ],\n        key: 'b',\n        text: 'Bravo',\n        type: 'unordered-list-item',\n      },\n      {\n        data: {},\n        depth: 0,\n        entityRanges: ([]: Array<EntityRange>),\n        inlineStyleRanges: [\n          {\n            length: 7,\n            offset: 0,\n            style: 'ITALIC',\n          },\n        ],\n        key: 'c',\n        text: 'Charlie',\n        type: 'blockquote',\n      },\n    ],\n    entityMap: {\n      '0': {\n        data: {},\n        mutability: 'IMMUTABLE',\n        type: 'IMAGE',\n      },\n    },\n  };\n\n  assertDraftState(rawState);\n});\n\ntest('must convert from raw tree draft to raw content state when experimentalTreeDataSupport is disabled', () => {\n  const rawState = {\n    blocks: [\n      {\n        key: 'A',\n        text: '',\n        entityRanges: ([]: Array<EntityRange>),\n        inlineStyleRanges: ([]: Array<InlineStyleRange>),\n        type: 'unstyled',\n        depth: 0,\n        children: [\n          {\n            key: 'B',\n            text: '',\n            entityRanges: ([]: Array<EntityRange>),\n            inlineStyleRanges: ([]: Array<InlineStyleRange>),\n            type: 'unstyled',\n            depth: 0,\n            children: [\n              {\n                key: 'C',\n                text: 'left block',\n                entityRanges: ([]: Array<EntityRange>),\n                inlineStyleRanges: ([]: Array<InlineStyleRange>),\n                type: 'unstyled',\n                depth: 0,\n                children: ([]: Array<RawDraftContentBlock>),\n              },\n              {\n                key: 'D',\n                text: 'right block',\n                entityRanges: ([]: Array<EntityRange>),\n                inlineStyleRanges: ([]: Array<InlineStyleRange>),\n                type: 'unstyled',\n                depth: 0,\n                children: ([]: Array<RawDraftContentBlock>),\n              },\n            ],\n          },\n          {\n            key: 'E',\n            type: 'header-one',\n            text: 'This is a tree based document!',\n            entityRanges: ([]: Array<EntityRange>),\n            inlineStyleRanges: ([]: Array<InlineStyleRange>),\n            depth: 0,\n            children: ([]: Array<RawDraftContentBlock>),\n          },\n        ],\n      },\n    ],\n    entityMap: {},\n  };\n\n  assertDraftState(rawState);\n});\n\ntest('convert from raw tree draft content state', () => {\n  toggleExperimentalTreeDataSupport(true);\n  const rawState = {\n    blocks: [\n      {\n        key: 'A',\n        text: '',\n        entityRanges: ([]: Array<EntityRange>),\n        depth: 0,\n        inlineStyleRanges: ([]: Array<InlineStyleRange>),\n        type: 'unstyled',\n        children: [\n          {\n            key: 'B',\n            text: '',\n            entityRanges: ([]: Array<EntityRange>),\n            depth: 0,\n            inlineStyleRanges: ([]: Array<InlineStyleRange>),\n            type: 'unstyled',\n            children: [\n              {\n                key: 'C',\n                text: 'left block',\n                entityRanges: ([]: Array<EntityRange>),\n                depth: 0,\n                inlineStyleRanges: ([]: Array<InlineStyleRange>),\n                type: 'unstyled',\n                children: ([]: Array<RawDraftContentBlock>),\n              },\n              {\n                key: 'D',\n                text: 'right block',\n                entityRanges: ([]: Array<EntityRange>),\n                depth: 0,\n                inlineStyleRanges: ([]: Array<InlineStyleRange>),\n                type: 'unstyled',\n                children: ([]: Array<RawDraftContentBlock>),\n              },\n            ],\n          },\n          {\n            key: 'E',\n            type: 'header-one',\n            text: 'This is a tree based document!',\n            entityRanges: ([]: Array<EntityRange>),\n            depth: 0,\n            inlineStyleRanges: ([]: Array<InlineStyleRange>),\n            children: ([]: Array<RawDraftContentBlock>),\n          },\n        ],\n      },\n    ],\n    entityMap: {},\n  };\n\n  assertDraftState(rawState);\n});\n\ntest('must be able to convert from raw state to tree state when experimentalTreeDataSupport is enabled', () => {\n  toggleExperimentalTreeDataSupport(true);\n  const rawState = {\n    blocks: [\n      {\n        key: 'A',\n        text: 'AAAA',\n        entityRanges: ([]: Array<EntityRange>),\n        type: 'unstyled',\n        inlineStyleRanges: ([]: Array<InlineStyleRange>),\n        depth: 0,\n      },\n      {\n        key: 'B',\n        text: 'BBBB',\n        entityRanges: ([]: Array<EntityRange>),\n        type: 'unstyled',\n        inlineStyleRanges: ([]: Array<InlineStyleRange>),\n        depth: 0,\n      },\n      {\n        key: 'C',\n        text: 'CCCC',\n        entityRanges: ([]: Array<EntityRange>),\n        type: 'unstyled',\n        inlineStyleRanges: ([]: Array<InlineStyleRange>),\n        depth: 0,\n      },\n    ],\n    entityMap: {},\n  };\n\n  assertDraftState(rawState);\n});\n\ntest('must be able to convert content blocks that have list with depth from raw state to tree state when experimentalTreeDataSupport is enabled', () => {\n  toggleExperimentalTreeDataSupport(true);\n  const rawState = {\n    blocks: [\n      {\n        key: 'A',\n        type: 'ordered-list-item',\n        depth: 0,\n        text: '',\n        entityRanges: ([]: Array<EntityRange>),\n        inlineStyleRanges: ([]: Array<InlineStyleRange>),\n      },\n      {\n        key: 'B',\n        type: 'ordered-list-item',\n        depth: 1,\n        text: '',\n        entityRanges: ([]: Array<EntityRange>),\n        inlineStyleRanges: ([]: Array<InlineStyleRange>),\n      },\n      {\n        key: 'C',\n        type: 'ordered-list-item',\n        depth: 2,\n        text: 'deeply nested list',\n        entityRanges: ([]: Array<EntityRange>),\n        inlineStyleRanges: ([]: Array<InlineStyleRange>),\n      },\n    ],\n    entityMap: {},\n  };\n\n  assertDraftState(rawState);\n});\n\ntest('ignore empty children array', () => {\n  const rawState = {\n    blocks: [\n      {\n        key: 'A',\n        type: 'ordered-list-item',\n        depth: 0,\n        text: 'A',\n        entityRanges: ([]: Array<EntityRange>),\n        inlineStyleRanges: ([]: Array<InlineStyleRange>),\n      },\n      {\n        key: 'B',\n        type: 'ordered-list-item',\n        depth: 0,\n        text: 'B',\n        entityRanges: ([]: Array<EntityRange>),\n        inlineStyleRanges: ([]: Array<InlineStyleRange>),\n      },\n      {\n        key: 'C',\n        type: 'ordered-list-item',\n        depth: 0,\n        text: 'C',\n        children: ([]: Array<RawDraftContentBlock>),\n        entityRanges: ([]: Array<EntityRange>),\n        inlineStyleRanges: ([]: Array<InlineStyleRange>),\n      },\n    ],\n    entityMap: {},\n  };\n\n  assertDraftState(rawState);\n});\n\ntest('ignore empty children array for tree conversion 1', () => {\n  const rawState = {\n    blocks: [\n      {\n        key: 'A',\n        type: 'ordered-list-item',\n        depth: 0,\n        text: 'A',\n        entityRanges: ([]: Array<EntityRange>),\n        inlineStyleRanges: ([]: Array<InlineStyleRange>),\n      },\n      {\n        key: 'B',\n        type: 'ordered-list-item',\n        depth: 0,\n        text: 'B',\n        entityRanges: ([]: Array<EntityRange>),\n        inlineStyleRanges: ([]: Array<InlineStyleRange>),\n      },\n      {\n        key: 'C',\n        type: 'ordered-list-item',\n        depth: 0,\n        text: 'C',\n        children: ([]: Array<RawDraftContentBlock>),\n        entityRanges: ([]: Array<EntityRange>),\n        inlineStyleRanges: ([]: Array<InlineStyleRange>),\n      },\n    ],\n    entityMap: {},\n  };\n  assertDraftState(rawState);\n});\n\ntest('ignore empty children array for tree conversion 2', () => {\n  toggleExperimentalTreeDataSupport(true);\n  const rawState = {\n    blocks: [\n      {\n        key: 'A',\n        type: 'ordered-list-item',\n        depth: 0,\n        text: 'A',\n        entityRanges: ([]: Array<EntityRange>),\n        inlineStyleRanges: ([]: Array<InlineStyleRange>),\n      },\n      {\n        key: 'B',\n        type: 'ordered-list-item',\n        depth: 0,\n        text: 'B',\n        entityRanges: ([]: Array<EntityRange>),\n        inlineStyleRanges: ([]: Array<InlineStyleRange>),\n      },\n      {\n        key: 'C',\n        type: 'ordered-list-item',\n        depth: 0,\n        text: 'C',\n        children: ([]: Array<RawDraftContentBlock>),\n        entityRanges: ([]: Array<EntityRange>),\n        inlineStyleRanges: ([]: Array<InlineStyleRange>),\n      },\n    ],\n    entityMap: {},\n  };\n  assertDraftState(rawState);\n});\n"
  },
  {
    "path": "src/model/encoding/__tests__/decodeEntityRanges-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst decodeEntityRanges = require('decodeEntityRanges');\n\ntest('must decode when no entities present', () => {\n  const decoded = decodeEntityRanges(' '.repeat(20), []);\n  expect(decoded).toMatchSnapshot();\n});\n\ntest('must decode when an entity is present', () => {\n  const decoded = decodeEntityRanges(' '.repeat(5), [\n    {\n      offset: 2,\n      length: 2,\n      key: 6,\n    },\n  ]);\n  expect(decoded).toMatchSnapshot();\n});\n\ntest('must decode when multiple entities present', () => {\n  const decoded = decodeEntityRanges(' '.repeat(8), [\n    {\n      offset: 2,\n      length: 2,\n      key: 6,\n    },\n    {\n      offset: 5,\n      length: 2,\n      key: 8,\n    },\n  ]);\n  expect(decoded).toMatchSnapshot();\n});\n\ntest('must decode when an entity is present more than once', () => {\n  const decoded = decodeEntityRanges(' '.repeat(8), [\n    {\n      offset: 2,\n      length: 2,\n      key: 6,\n    },\n    {\n      offset: 5,\n      length: 2,\n      key: 6,\n    },\n  ]);\n  expect(decoded).toMatchSnapshot();\n});\n\ntest('must handle ranges that include surrogate pairs', () => {\n  const decoded = decodeEntityRanges('Take a \\uD83D\\uDCF7 #selfie', [\n    {\n      offset: 6,\n      length: 5,\n      key: 6,\n    },\n    {\n      offset: 13,\n      length: 2,\n      key: 8,\n    },\n  ]);\n  expect(decoded).toMatchSnapshot();\n});\n"
  },
  {
    "path": "src/model/encoding/__tests__/decodeInlineStyleRanges-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {InlineStyleRange} from 'InlineStyleRange';\n\nconst decodeInlineStyleRanges = require('decodeInlineStyleRanges');\n\ntest('must decode for an unstyled block', () => {\n  const block = {\n    text: 'Hello',\n    inlineStyleRanges: ([]: Array<InlineStyleRange>),\n  };\n  expect(\n    decodeInlineStyleRanges(block.text, block.inlineStyleRanges).map(r =>\n      r.toJS(),\n    ),\n  ).toMatchSnapshot();\n});\n\ntest('must decode for a flat styled block', () => {\n  const block = {\n    text: 'Hello',\n    inlineStyleRanges: [{style: 'BOLD', offset: 0, length: 5}],\n  };\n  expect(\n    decodeInlineStyleRanges(block.text, block.inlineStyleRanges).map(r =>\n      r.toJS(),\n    ),\n  ).toMatchSnapshot();\n});\n\ntest('must decode for a mixed-style block', () => {\n  const block = {\n    text: 'Hello',\n    inlineStyleRanges: [\n      {style: 'BOLD', offset: 0, length: 3},\n      {style: 'ITALIC', offset: 1, length: 3},\n      {style: 'UNDERLINE', offset: 0, length: 2},\n      {style: 'BOLD', offset: 4, length: 1},\n    ],\n  };\n  expect(\n    decodeInlineStyleRanges(block.text, block.inlineStyleRanges).map(r =>\n      r.toJS(),\n    ),\n  ).toMatchSnapshot();\n});\n\ntest('must decode for strings that contain surrogate pairs in UTF-16', () => {\n  const block = {\n    text: 'Take a \\uD83D\\uDCF7 #selfie',\n    inlineStyleRanges: [\n      {offset: 4, length: 4, style: 'BOLD'},\n      {offset: 6, length: 8, style: 'ITALIC'},\n    ],\n  };\n\n  expect(\n    decodeInlineStyleRanges(block.text, block.inlineStyleRanges).map(r =>\n      r.toJS(),\n    ),\n  ).toMatchSnapshot();\n});\n"
  },
  {
    "path": "src/model/encoding/__tests__/encodeEntityRanges-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst ContentBlock = require('ContentBlock');\n\nconst createCharacterList = require('createCharacterList');\nconst encodeEntityRanges = require('encodeEntityRanges');\nconst Immutable = require('immutable');\n\nconst {OrderedSet, Repeat} = Immutable;\n\nconst createBlock = (text: string, entities: Array<?string>) => {\n  const style = OrderedSet<string>();\n  return new ContentBlock({\n    key: 'a',\n    text,\n    type: 'unstyled',\n    characterList: createCharacterList(\n      Repeat(style, text.length).toArray(),\n      entities,\n    ),\n  });\n};\n\ntest('must return an empty array if no entities present', () => {\n  const block = createBlock(' '.repeat(20), Repeat(null, 20).toArray());\n  let encoded = encodeEntityRanges(block, {});\n  expect(encoded).toMatchSnapshot();\n\n  encoded = encodeEntityRanges(block, {'0': '0'});\n  expect(encoded).toMatchSnapshot();\n});\n\ntest('must return ranges with the storage-mapped key', () => {\n  const entities = [null, null, '6', '6', null];\n  const block = createBlock(' '.repeat(entities.length), entities);\n  const encoded = encodeEntityRanges(block, {_6: '0'});\n  expect(encoded).toMatchSnapshot();\n});\n\ntest('must return ranges with multiple entities present', () => {\n  const entities = [null, null, '6', '6', null, '8', '8', null];\n  const block = createBlock(' '.repeat(entities.length), entities);\n  const encoded = encodeEntityRanges(block, {_6: '0', _8: '1'});\n  expect(encoded).toMatchSnapshot();\n});\n\ntest('must return ranges with an entity present more than once', () => {\n  const entities = [null, null, '6', '6', null, '6', '6', null];\n  const block = createBlock(' '.repeat(entities.length), entities);\n  const encoded = encodeEntityRanges(block, {_6: '0', _8: '1'});\n  expect(encoded).toMatchSnapshot();\n});\n\ntest('must handle ranges that include surrogate pairs', () => {\n  const str = 'Take a \\uD83D\\uDCF7 #selfie';\n  // prettier-ignore\n  const entities = [\n      null, null, null, null, null, null, // `Take a`\n      '6', '6', '6', '6', '6', '6',       // ` [camera] #s`\n      null, null, '8', '8', null,         // `elfie`\n    ];\n\n  const block = createBlock(str, entities);\n  const encoded = encodeEntityRanges(block, {_6: '0', _8: '1'});\n  expect(encoded).toMatchSnapshot();\n});\n"
  },
  {
    "path": "src/model/encoding/__tests__/encodeInlineStyleRanges-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst ContentBlock = require('ContentBlock');\nconst SampleDraftInlineStyle = require('SampleDraftInlineStyle');\n\nconst createCharacterList = require('createCharacterList');\nconst encodeInlineStyleRanges = require('encodeInlineStyleRanges');\nconst Immutable = require('immutable');\n\nconst {\n  BOLD,\n  BOLD_ITALIC,\n  BOLD_UNDERLINE,\n  BOLD_ITALIC_UNDERLINE,\n  ITALIC,\n  ITALIC_UNDERLINE,\n  NONE,\n} = SampleDraftInlineStyle;\n\nconst {List, OrderedSet, Repeat} = Immutable;\n\nconst FOO = OrderedSet.of('foo');\nconst FOO_BAR = OrderedSet.of('foo', 'bar');\n\n/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's\n * LTI update could not be added via codemod */\nconst createBlock = (text: string, inlineStyles) => {\n  return new ContentBlock({\n    key: 'a',\n    text,\n    type: 'unstyled',\n    characterList: createCharacterList(\n      inlineStyles.toArray(),\n      Repeat(null, text.length).toArray(),\n    ),\n  });\n};\n\ntest('must encode for an unstyled document', () => {\n  expect(\n    encodeInlineStyleRanges(createBlock(' '.repeat(2), Repeat(NONE, 2))),\n  ).toMatchSnapshot();\n  expect(\n    encodeInlineStyleRanges(createBlock(' '.repeat(20), Repeat(NONE, 20))),\n  ).toMatchSnapshot();\n  expect(\n    encodeInlineStyleRanges(createBlock(' '.repeat(200), Repeat(NONE, 200))),\n  ).toMatchSnapshot();\n  expect(\n    encodeInlineStyleRanges(createBlock(' '.repeat(2000), Repeat(NONE, 2000))),\n  ).toMatchSnapshot();\n});\n\ntest('must encode for a flat styled document', () => {\n  const all = BOLD_ITALIC_UNDERLINE;\n  expect(\n    encodeInlineStyleRanges(createBlock(' '.repeat(20), Repeat(BOLD, 20))),\n  ).toMatchSnapshot();\n  expect(\n    encodeInlineStyleRanges(\n      createBlock(' '.repeat(20), Repeat(BOLD_ITALIC, 20)),\n    ),\n  ).toMatchSnapshot();\n  expect(\n    encodeInlineStyleRanges(createBlock(' '.repeat(20), Repeat(all, 20))),\n  ).toMatchSnapshot();\n});\n\ntest('must encode custom styles', () => {\n  const custom = List([FOO, FOO, FOO_BAR, FOO_BAR, BOLD, BOLD]);\n  expect(\n    encodeInlineStyleRanges(createBlock(' '.repeat(6), custom)),\n  ).toMatchSnapshot();\n});\n\ntest('must encode for a complex styled document', () => {\n  // prettier-ignore\n  const complex = List([\n      BOLD, BOLD, BOLD, BOLD, NONE,     // \"four \"\n      BOLD_ITALIC, BOLD_ITALIC,         // \"sc\"\n      ITALIC_UNDERLINE, BOLD_UNDERLINE, // \"or\"\n      BOLD_ITALIC_UNDERLINE,            // \"e\"\n    ]);\n\n  expect(\n    encodeInlineStyleRanges(createBlock(' '.repeat(10), complex)),\n  ).toMatchSnapshot();\n});\n\ntest('must encode for strings with surrogate pairs', () => {\n  const str = 'Take a \\uD83D\\uDCF7 #selfie';\n  // prettier-ignore\n  const styles = List([\n      NONE, NONE, NONE, NONE,                            // `Take`\n      BOLD, BOLD, BOLD_ITALIC, BOLD_ITALIC, BOLD_ITALIC, // ` a [camera]`\n      ITALIC, ITALIC, ITALIC, ITALIC, ITALIC, ITALIC,    // ` #self`\n      NONE, NONE,                                        // `ie`\n    ]);\n\n  expect(encodeInlineStyleRanges(createBlock(str, styles))).toMatchSnapshot();\n});\n"
  },
  {
    "path": "src/model/encoding/__tests__/sanitizeDraftText-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\nconst sanitizeDraftText = require('sanitizeDraftText');\n\ntest('must strip trailing carriage returns', () => {\n  expect(sanitizeDraftText('test\\u000d')).toMatchSnapshot();\n});\n\ntest('must strip two trailing carriage returns', () => {\n  expect(sanitizeDraftText('test\\u000d\\u000d')).toMatchSnapshot();\n});\n\ntest('must strip within carriage returns', () => {\n  expect(sanitizeDraftText('te\\u000dst')).toMatchSnapshot();\n});\n\ntest('must strip leading carriage returns', () => {\n  expect(sanitizeDraftText('\\u000dtest')).toMatchSnapshot();\n});\n\ntest('must strip all carriage returns', () => {\n  expect(\n    sanitizeDraftText('\\u000dt\\u000des\\u000dt\\u000d\\u000d'),\n  ).toMatchSnapshot();\n});\n"
  },
  {
    "path": "src/model/encoding/convertFromDraftStateToRaw.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type ContentState from 'ContentState';\nimport type {DraftEntityMutability} from 'DraftEntityMutability';\nimport type {DraftEntityType} from 'DraftEntityType';\nimport type {RawDraftContentBlock} from 'RawDraftContentBlock';\nimport type {RawDraftContentState} from 'RawDraftContentState';\nimport type {RawDraftEntity} from 'RawDraftEntity';\n\nconst ContentBlock = require('ContentBlock');\nconst ContentBlockNode = require('ContentBlockNode');\nconst DraftStringKey = require('DraftStringKey');\n\nconst encodeEntityRanges = require('encodeEntityRanges');\nconst encodeInlineStyleRanges = require('encodeInlineStyleRanges');\nconst invariant = require('invariant');\n\nconst createRawBlock = (\n  block: BlockNodeRecord,\n  entityStorageMap: {[key: string]: RawDraftEntity},\n) => {\n  return {\n    key: block.getKey(),\n    text: block.getText(),\n    type: block.getType(),\n    depth: block.getDepth(),\n    inlineStyleRanges: encodeInlineStyleRanges(block),\n    entityRanges: encodeEntityRanges(block, entityStorageMap),\n    data: block.getData().toObject(),\n  };\n};\n\nconst insertRawBlock = (\n  block: BlockNodeRecord,\n  entityMap: {[key: string]: RawDraftEntity},\n  rawBlocks: Array<RawDraftContentBlock>,\n  blockCacheRef: {...},\n) => {\n  if (block instanceof ContentBlock) {\n    rawBlocks.push(createRawBlock(block, entityMap));\n    return;\n  }\n\n  invariant(block instanceof ContentBlockNode, 'block is not a BlockNode');\n\n  const parentKey = block.getParentKey();\n  // $FlowFixMe[prop-missing]\n  const rawBlock = (blockCacheRef[block.getKey()] = {\n    ...createRawBlock(block, entityMap),\n    children: [],\n  });\n\n  if (parentKey) {\n    blockCacheRef[parentKey].children.push(rawBlock);\n    return;\n  }\n\n  rawBlocks.push(rawBlock);\n};\n\nconst encodeRawBlocks = (\n  contentState: ContentState,\n  rawState: RawDraftContentState,\n): RawDraftContentState => {\n  const {entityMap} = rawState;\n\n  const rawBlocks: Array<RawDraftContentBlock> = [];\n\n  const blockCacheRef = {};\n  const entityCacheRef: {[string]: ?string} = {};\n  let entityStorageKey = 0;\n\n  contentState.getBlockMap().forEach(block => {\n    block.findEntityRanges(\n      character => character.getEntity() !== null,\n      start => {\n        const entityKey = block.getEntityAt(start);\n        // Stringify to maintain order of otherwise numeric keys.\n        const stringifiedEntityKey = DraftStringKey.stringify(entityKey);\n        // This makes this function resilient to two entities\n        // erroneously having the same key\n        if (entityCacheRef[stringifiedEntityKey]) {\n          return;\n        }\n        entityCacheRef[stringifiedEntityKey] = entityKey;\n        // we need the `any` casting here since this is a temporary state\n        // where we will later on flip the entity map and populate it with\n        // real entity, at this stage we just need to map back the entity\n        // key used by the BlockNode\n        entityMap[stringifiedEntityKey] = (`${entityStorageKey}`: any);\n        entityStorageKey++;\n      },\n    );\n\n    insertRawBlock(block, entityMap, rawBlocks, blockCacheRef);\n  });\n\n  return {\n    blocks: rawBlocks,\n    entityMap,\n  };\n};\n\n// Flip storage map so that our storage keys map to global\n// DraftEntity keys.\nconst encodeRawEntityMap = (\n  contentState: ContentState,\n  rawState: RawDraftContentState,\n): RawDraftContentState => {\n  const {blocks, entityMap} = rawState;\n\n  const rawEntityMap: {\n    [number]: {\n      data: any,\n      mutability: DraftEntityMutability,\n      type: DraftEntityType,\n    },\n  } = {};\n\n  Object.keys(entityMap).forEach((key, index) => {\n    const entity = contentState.getEntity(DraftStringKey.unstringify(key));\n    rawEntityMap[index] = {\n      type: entity.getType(),\n      mutability: entity.getMutability(),\n      data: entity.getData(),\n    };\n  });\n\n  return {\n    blocks,\n    // $FlowFixMe[incompatible-exact]\n    // $FlowFixMe[incompatible-return]\n    entityMap: rawEntityMap,\n  };\n};\n\nconst convertFromDraftStateToRaw = (\n  contentState: ContentState,\n): RawDraftContentState => {\n  let rawDraftContentState = {\n    entityMap: {},\n    blocks: ([]: Array<RawDraftContentBlock>),\n  };\n\n  // add blocks\n  // $FlowFixMe[prop-missing]\n  rawDraftContentState = encodeRawBlocks(contentState, rawDraftContentState);\n\n  // add entities\n  // $FlowFixMe[prop-missing]\n  rawDraftContentState = encodeRawEntityMap(contentState, rawDraftContentState);\n\n  return rawDraftContentState;\n};\n\nmodule.exports = convertFromDraftStateToRaw;\n"
  },
  {
    "path": "src/model/encoding/convertFromHTMLToContentBlocks.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type {DraftBlockRenderMap} from 'DraftBlockRenderMap';\nimport type {DraftInlineStyle} from 'DraftInlineStyle';\nimport type {EntityMap} from 'EntityMap';\n\nconst CharacterMetadata = require('CharacterMetadata');\nconst ContentBlock = require('ContentBlock');\nconst ContentBlockNode = require('ContentBlockNode');\nconst ContentState = require('ContentState');\nconst DefaultDraftBlockRenderMap = require('DefaultDraftBlockRenderMap');\nconst URI = require('URI');\n\nconst cx = require('cx');\nconst generateRandomKey = require('generateRandomKey');\nconst getSafeBodyFromHTML = require('getSafeBodyFromHTML');\nconst gkx = require('gkx');\nconst {List, Map, OrderedSet} = require('immutable');\nconst isHTMLAnchorElement = require('isHTMLAnchorElement');\nconst isHTMLBRElement = require('isHTMLBRElement');\nconst isHTMLElement = require('isHTMLElement');\nconst isHTMLImageElement = require('isHTMLImageElement');\n\nconst experimentalTreeDataSupport = gkx('draft_tree_data_support');\nconst allowPastingAltText = gkx('draftjs_paste_emojis');\n\nconst NBSP = '&nbsp;';\nconst SPACE = ' ';\n\n// used for replacing characters in HTML\nconst REGEX_CR = new RegExp('\\r', 'g');\nconst REGEX_LF = new RegExp('\\n', 'g');\nconst REGEX_LEADING_LF = new RegExp('^\\n', 'g');\nconst REGEX_NBSP = new RegExp(NBSP, 'g');\nconst REGEX_CARRIAGE = new RegExp('&#13;?', 'g');\nconst REGEX_ZWS = new RegExp('&#8203;?', 'g');\n\n// https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight\nconst boldValues = ['bold', 'bolder', '500', '600', '700', '800', '900'];\nconst notBoldValues = [\n  'light',\n  'lighter',\n  'normal',\n  '100',\n  '200',\n  '300',\n  '400',\n];\n\nconst anchorAttr = ['className', 'href', 'rel', 'target', 'title'];\nconst imgAttr = ['alt', 'className', 'height', 'src', 'width'];\n\nconst knownListItemDepthClasses = {\n  [cx('public/DraftStyleDefault/depth0')]: 0,\n  [cx('public/DraftStyleDefault/depth1')]: 1,\n  [cx('public/DraftStyleDefault/depth2')]: 2,\n  [cx('public/DraftStyleDefault/depth3')]: 3,\n  [cx('public/DraftStyleDefault/depth4')]: 4,\n};\n\nconst HTMLTagToRawInlineStyleMap: Map<string, string> = Map({\n  b: 'BOLD',\n  code: 'CODE',\n  del: 'STRIKETHROUGH',\n  em: 'ITALIC',\n  i: 'ITALIC',\n  s: 'STRIKETHROUGH',\n  strike: 'STRIKETHROUGH',\n  strong: 'BOLD',\n  u: 'UNDERLINE',\n  mark: 'HIGHLIGHT',\n});\n\ntype BlockTypeMap = Map<string, string | Array<string>>;\n\n/**\n * Build a mapping from HTML tags to draftjs block types\n * out of a BlockRenderMap.\n *\n * The BlockTypeMap for the default BlockRenderMap looks like this:\n *   Map({\n *     h1: 'header-one',\n *     h2: 'header-two',\n *     h3: 'header-three',\n *     h4: 'header-four',\n *     h5: 'header-five',\n *     h6: 'header-six',\n *     blockquote: 'blockquote',\n *     figure: 'atomic',\n *     pre: ['code-block'],\n *     div: 'unstyled',\n *     p: 'unstyled',\n *     li: ['ordered-list-item', 'unordered-list-item'],\n *   })\n */\nconst buildBlockTypeMap = (\n  blockRenderMap: DraftBlockRenderMap,\n): BlockTypeMap => {\n  const blockTypeMap: {[string]: any | Array<any | string>} = {};\n\n  blockRenderMap.mapKeys((blockType, desc) => {\n    const elements = [desc.element];\n    if (desc.aliasedElements !== undefined) {\n      elements.push(...desc.aliasedElements);\n    }\n    elements.forEach(element => {\n      if (blockTypeMap[element] === undefined) {\n        blockTypeMap[element] = blockType;\n      } else if (typeof blockTypeMap[element] === 'string') {\n        blockTypeMap[element] = [blockTypeMap[element], blockType];\n      } else {\n        blockTypeMap[element].push(blockType);\n      }\n    });\n  });\n\n  return Map(blockTypeMap);\n};\n\nconst detectInlineStyle = (node: Node): string | null => {\n  if (isHTMLElement(node)) {\n    const element: HTMLElement = (node: any);\n    // Currently only used to detect preformatted inline code\n    if (element.style.fontFamily.includes('monospace')) {\n      return 'CODE';\n    }\n  }\n  return null;\n};\n\n/**\n * If we're pasting from one DraftEditor to another we can check to see if\n * existing list item depth classes are being used and preserve this style\n */\nconst getListItemDepth = (node: HTMLElement, depth: number = 0): number => {\n  Object.keys(knownListItemDepthClasses).some(depthClass => {\n    if (node.classList.contains(depthClass)) {\n      depth = knownListItemDepthClasses[depthClass];\n    }\n  });\n  return depth;\n};\n\n/**\n * Return true if the provided HTML Element can be used to build a\n * Draftjs-compatible link.\n */\nconst isValidAnchor = (node: Node) => {\n  if (!isHTMLAnchorElement(node)) {\n    return false;\n  }\n  const anchorNode: HTMLAnchorElement = (node: any);\n\n  if (\n    !anchorNode.href ||\n    (anchorNode.protocol !== 'http:' &&\n      anchorNode.protocol !== 'https:' &&\n      anchorNode.protocol !== 'mailto:' &&\n      anchorNode.protocol !== 'tel:')\n  ) {\n    return false;\n  }\n\n  try {\n    // Just checking whether we can actually create a URI\n    const _ = new URI(anchorNode.href);\n    return true;\n  } catch {\n    return false;\n  }\n};\n\n/**\n * Return true if the provided HTML Element can be used to build a\n * Draftjs-compatible image.\n */\nconst isValidImage = (node: Node): boolean => {\n  if (!isHTMLImageElement(node)) {\n    return false;\n  }\n  const imageNode: HTMLImageElement = (node: any);\n  return !!(\n    imageNode.attributes.getNamedItem('src') &&\n    imageNode.attributes.getNamedItem('src').value\n  );\n};\n\n/**\n * Try to guess the inline style of an HTML element based on its css\n * styles (font-weight, font-style and text-decoration).\n */\nconst styleFromNodeAttributes = (\n  node: Node,\n  style: DraftInlineStyle,\n): DraftInlineStyle => {\n  if (!isHTMLElement(node)) {\n    return style;\n  }\n\n  const htmlElement: HTMLElement = (node: any);\n  const fontWeight = htmlElement.style.fontWeight;\n  const fontStyle = htmlElement.style.fontStyle;\n  const textDecoration = htmlElement.style.textDecoration;\n\n  return style.withMutations(style => {\n    if (boldValues.indexOf(fontWeight) >= 0) {\n      style.add('BOLD');\n    } else if (notBoldValues.indexOf(fontWeight) >= 0) {\n      style.remove('BOLD');\n    }\n\n    if (fontStyle === 'italic') {\n      style.add('ITALIC');\n    } else if (fontStyle === 'normal') {\n      style.remove('ITALIC');\n    }\n\n    if (textDecoration === 'underline') {\n      style.add('UNDERLINE');\n    }\n    if (textDecoration === 'line-through') {\n      style.add('STRIKETHROUGH');\n    }\n    if (textDecoration === 'none') {\n      style.remove('UNDERLINE');\n      style.remove('STRIKETHROUGH');\n    }\n  });\n};\n\n/**\n * Determine if a nodeName is a list type, 'ul' or 'ol'\n */\nconst isListNode = (nodeName: ?string): boolean =>\n  nodeName === 'ul' || nodeName === 'ol';\n\n/**\n *  ContentBlockConfig is a mutable data structure that holds all\n *  the information required to build a ContentBlock and an array of\n *  all the child nodes (childConfigs).\n *  It is being used a temporary data structure by the\n *  ContentBlocksBuilder class.\n */\ntype ContentBlockConfig = {\n  characterList: List<CharacterMetadata>,\n  data?: Map<any, any>,\n  depth?: number,\n  key: string,\n  text: string,\n  type: string,\n  children: List<string>,\n  parent: ?string,\n  prevSibling: ?string,\n  nextSibling: ?string,\n  childConfigs: Array<ContentBlockConfig>,\n  ...\n};\n\n/**\n * ContentBlocksBuilder builds a list of ContentBlocks and an Entity Map\n * out of one (or several) HTMLElement(s).\n *\n * The algorithm has two passes: first it builds a tree of ContentBlockConfigs\n * by walking through the HTML nodes and their children, then it walks the\n * ContentBlockConfigs tree to compute parents/siblings and create\n * the actual ContentBlocks.\n *\n * Typical usage is:\n *     new ContentBlocksBuilder()\n *        .addDOMNode(someHTMLNode)\n *        .addDOMNode(someOtherHTMLNode)\n *       .getContentBlocks();\n *\n */\nclass ContentBlocksBuilder {\n  // Most of the method in the class depend on the state of the content builder\n  // (i.e. currentBlockType, currentDepth, currentEntity etc.). Though it may\n  // be confusing at first, it made the code simpler than the alternative which\n  // is to pass those values around in every call.\n\n  // The following attributes are used to accumulate text and styles\n  // as we are walking the HTML node tree.\n  characterList: List<CharacterMetadata> = List();\n  currentBlockType: string = 'unstyled';\n  currentDepth: number = 0;\n  currentEntity: ?string = null;\n  currentText: string = '';\n  wrapper: ?string = null;\n\n  // Describes the future ContentState as a tree of content blocks\n  blockConfigs: Array<ContentBlockConfig> = [];\n\n  // The content blocks generated from the blockConfigs\n  contentBlocks: Array<BlockNodeRecord> = [];\n\n  // Entity map use to store links and images found in the HTML nodes\n  contentState: ContentState = ContentState.createFromText('');\n\n  // Map HTML tags to draftjs block types and disambiguation function\n  blockTypeMap: BlockTypeMap;\n  disambiguate: (string, ?string) => ?string;\n\n  constructor(\n    blockTypeMap: BlockTypeMap,\n    disambiguate: (string, ?string) => ?string,\n  ): void {\n    this.clear();\n    this.blockTypeMap = blockTypeMap;\n    this.disambiguate = disambiguate;\n  }\n\n  /**\n   * Clear the internal state of the ContentBlocksBuilder\n   */\n  clear(): void {\n    this.characterList = List();\n    this.blockConfigs = [];\n    this.currentBlockType = 'unstyled';\n    this.currentDepth = 0;\n    this.currentEntity = null;\n    this.currentText = '';\n    this.contentState = ContentState.createFromText('');\n    this.wrapper = null;\n    this.contentBlocks = [];\n  }\n\n  /**\n   * Add an HTMLElement to the ContentBlocksBuilder\n   */\n  addDOMNode(node: Node): ContentBlocksBuilder {\n    this.contentBlocks = [];\n    this.currentDepth = 0;\n    // Converts the HTML node to block config\n    this.blockConfigs.push(...this._toBlockConfigs([node], OrderedSet()));\n\n    // There might be some left over text in the builder's\n    // internal state, if so make a ContentBlock out of it.\n    this._trimCurrentText();\n    if (this.currentText !== '') {\n      this.blockConfigs.push(this._makeBlockConfig());\n    }\n\n    // for chaining\n    return this;\n  }\n\n  /**\n   * Return the ContentBlocks and the EntityMap that corresponds\n   * to the previously added HTML nodes.\n   */\n  getContentBlocks(): {\n    contentBlocks: ?Array<BlockNodeRecord>,\n    entityMap: EntityMap,\n    ...\n  } {\n    if (this.contentBlocks.length === 0) {\n      if (experimentalTreeDataSupport) {\n        this._toContentBlocks(this.blockConfigs);\n      } else {\n        this._toFlatContentBlocks(this.blockConfigs);\n      }\n    }\n    return {\n      contentBlocks: this.contentBlocks,\n      entityMap: this.contentState.getEntityMap(),\n    };\n  }\n\n  // ***********************************WARNING******************************\n  // The methods below this line are private - don't call them directly.\n\n  /**\n   * Generate a new ContentBlockConfig out of the current internal state\n   * of the builder, then clears the internal state.\n   */\n  _makeBlockConfig(config: Object = {}): ContentBlockConfig {\n    const key = config.key || generateRandomKey();\n    const block = {\n      key,\n      type: this.currentBlockType,\n      text: this.currentText,\n      characterList: this.characterList,\n      depth: this.currentDepth,\n      parent: null,\n      children: List<mixed>(),\n      prevSibling: null,\n      nextSibling: null,\n      childConfigs: [],\n      ...config,\n    };\n    this.characterList = List();\n    this.currentBlockType = 'unstyled';\n    this.currentText = '';\n    return block;\n  }\n\n  /**\n   * Converts an array of HTML elements to a multi-root tree of content\n   * block configs. Some text content may be left in the builders internal\n   * state to enable chaining sucessive calls.\n   */\n  _toBlockConfigs(\n    nodes: Array<Node>,\n    style: DraftInlineStyle,\n  ): Array<ContentBlockConfig> {\n    const blockConfigs = [];\n    for (let i = 0; i < nodes.length; i++) {\n      const node = nodes[i];\n      const nodeName = node.nodeName.toLowerCase();\n\n      if (nodeName === 'body' || isListNode(nodeName)) {\n        // body, ol and ul are 'block' type nodes so create a block config\n        // with the text accumulated so far (if any)\n        this._trimCurrentText();\n        if (this.currentText !== '') {\n          blockConfigs.push(this._makeBlockConfig());\n        }\n\n        // body, ol and ul nodes are ignored, but their children are inlined in\n        // the parent block config.\n        const wasCurrentDepth = this.currentDepth;\n        const wasWrapper = this.wrapper;\n        if (isListNode(nodeName)) {\n          this.wrapper = nodeName;\n          if (isListNode(wasWrapper)) {\n            this.currentDepth++;\n          }\n        }\n        blockConfigs.push(\n          ...this._toBlockConfigs(Array.from(node.childNodes), style),\n        );\n        this.currentDepth = wasCurrentDepth;\n        this.wrapper = wasWrapper;\n        continue;\n      }\n\n      let blockType = this.blockTypeMap.get(nodeName);\n      if (blockType !== undefined) {\n        // 'block' type node means we need to create a block config\n        // with the text accumulated so far (if any)\n        this._trimCurrentText();\n        if (this.currentText !== '') {\n          blockConfigs.push(this._makeBlockConfig());\n        }\n\n        const wasCurrentDepth = this.currentDepth;\n        const wasWrapper = this.wrapper;\n        this.wrapper = nodeName === 'pre' ? 'pre' : this.wrapper;\n\n        if (typeof blockType !== 'string') {\n          blockType =\n            this.disambiguate(nodeName, this.wrapper) ||\n            blockType[0] ||\n            'unstyled';\n        }\n\n        if (\n          !experimentalTreeDataSupport &&\n          isHTMLElement(node) &&\n          (blockType === 'unordered-list-item' ||\n            blockType === 'ordered-list-item')\n        ) {\n          const htmlElement: HTMLElement = (node: any);\n          this.currentDepth = getListItemDepth(htmlElement, this.currentDepth);\n        }\n\n        const key = generateRandomKey();\n        const childConfigs = this._toBlockConfigs(\n          Array.from(node.childNodes),\n          style,\n        );\n        this._trimCurrentText();\n        blockConfigs.push(\n          this._makeBlockConfig({\n            key,\n            childConfigs,\n            type: blockType,\n          }),\n        );\n\n        this.currentDepth = wasCurrentDepth;\n        this.wrapper = wasWrapper;\n        continue;\n      }\n\n      if (nodeName === '#text') {\n        this._addTextNode(node, style);\n        continue;\n      }\n\n      if (nodeName === 'br') {\n        this._addBreakNode(node, style);\n        continue;\n      }\n\n      if (isValidImage(node)) {\n        this._addImgNode(node, style);\n        continue;\n      }\n\n      if (isValidAnchor(node)) {\n        this._addAnchorNode(node, blockConfigs, style);\n        continue;\n      }\n\n      let newStyle = style;\n      if (HTMLTagToRawInlineStyleMap.has(nodeName)) {\n        newStyle = newStyle.add(HTMLTagToRawInlineStyleMap.get(nodeName));\n      }\n      newStyle = styleFromNodeAttributes(node, newStyle);\n      const inlineStyle = detectInlineStyle(node);\n      if (inlineStyle != null) {\n        newStyle = newStyle.add(inlineStyle);\n      }\n      blockConfigs.push(\n        ...this._toBlockConfigs(Array.from(node.childNodes), newStyle),\n      );\n    }\n\n    return blockConfigs;\n  }\n\n  /**\n   * Append a string of text to the internal buffer.\n   */\n  _appendText(text: string, style: DraftInlineStyle) {\n    this.currentText += text;\n    const characterMetadata = CharacterMetadata.create({\n      style,\n      entity: this.currentEntity,\n    });\n    this.characterList = this.characterList.push(\n      ...Array(text.length).fill(characterMetadata),\n    );\n  }\n\n  /**\n   * Trim the text in the internal buffer.\n   */\n  _trimCurrentText() {\n    const l = this.currentText.length;\n    let begin = l - this.currentText.trimLeft().length;\n    let end = this.currentText.trimRight().length;\n\n    // We should not trim whitespaces for which an entity is defined.\n    let entity = this.characterList.findEntry(\n      characterMetadata => characterMetadata.getEntity() !== null,\n    );\n    begin = entity !== undefined ? Math.min(begin, entity[0]) : begin;\n\n    entity = this.characterList\n      .reverse()\n      .findEntry(characterMetadata => characterMetadata.getEntity() !== null);\n    end = entity !== undefined ? Math.max(end, l - entity[0]) : end;\n\n    if (begin > end) {\n      this.currentText = '';\n      this.characterList = List();\n    } else {\n      this.currentText = this.currentText.slice(begin, end);\n      this.characterList = this.characterList.slice(begin, end);\n    }\n  }\n\n  /**\n   * Add the content of an HTML text node to the internal state\n   */\n  _addTextNode(node: Node, style: DraftInlineStyle) {\n    let text = node.textContent;\n    const trimmedText = text.trim();\n\n    // If we are not in a pre block and the trimmed content is empty,\n    // normalize to a single space.\n    if (trimmedText === '' && this.wrapper !== 'pre') {\n      text = ' ';\n    }\n\n    if (this.wrapper !== 'pre') {\n      // Trim leading line feed, which is invisible in HTML\n      text = text.replace(REGEX_LEADING_LF, '');\n\n      // Can't use empty string because MSWord\n      text = text.replace(REGEX_LF, SPACE);\n    }\n\n    this._appendText(text, style);\n  }\n\n  _addBreakNode(node: Node, style: DraftInlineStyle) {\n    if (!isHTMLBRElement(node)) {\n      return;\n    }\n    this._appendText('\\n', style);\n  }\n\n  /**\n   * Add the content of an HTML img node to the internal state\n   */\n  _addImgNode(node: Node, style: DraftInlineStyle) {\n    if (!isHTMLImageElement(node)) {\n      return;\n    }\n    const image: HTMLImageElement = (node: any);\n    const entityConfig: {[string]: string} = {};\n\n    imgAttr.forEach(attr => {\n      const imageAttribute = image.getAttribute(attr);\n      if (imageAttribute) {\n        entityConfig[attr] = imageAttribute;\n      }\n    });\n\n    this.contentState = this.contentState.createEntity(\n      'IMAGE',\n      'IMMUTABLE',\n      entityConfig,\n    );\n    this.currentEntity = this.contentState.getLastCreatedEntityKey();\n\n    // The child text node cannot just have a space or return as content (since\n    // we strip those out)\n    const alt = image.getAttribute('alt');\n    if (allowPastingAltText && alt != null && alt.length > 0) {\n      this._appendText(alt, style);\n    } else {\n      this._appendText('\\ud83d\\udcf7', style);\n    }\n    this.currentEntity = null;\n  }\n\n  /**\n   * Add the content of an HTML 'a' node to the internal state. Child nodes\n   * (if any) are converted to Block Configs and appended to the provided\n   * blockConfig array.\n   */\n  _addAnchorNode(\n    node: Node,\n    blockConfigs: Array<ContentBlockConfig>,\n    style: DraftInlineStyle,\n  ) {\n    // The check has already been made by isValidAnchor but\n    // we have to do it again to keep flow happy.\n    if (!isHTMLAnchorElement(node)) {\n      return;\n    }\n    const anchor: HTMLAnchorElement = (node: any);\n    const entityConfig: {[string]: string} = {};\n\n    anchorAttr.forEach(attr => {\n      const anchorAttribute = anchor.getAttribute(attr);\n      if (anchorAttribute) {\n        entityConfig[attr] = anchorAttribute;\n      }\n    });\n\n    entityConfig.url = new URI(anchor.href).toString();\n\n    this.contentState = this.contentState.createEntity(\n      'LINK',\n      'MUTABLE',\n      entityConfig || {},\n    );\n    this.currentEntity = this.contentState.getLastCreatedEntityKey();\n\n    blockConfigs.push(\n      ...this._toBlockConfigs(Array.from(node.childNodes), style),\n    );\n    this.currentEntity = null;\n  }\n\n  /**\n   * Walk the BlockConfig tree, compute parent/children/siblings,\n   * and generate the corresponding ContentBlockNode\n   */\n  _toContentBlocks(\n    blockConfigs: Array<ContentBlockConfig>,\n    parent: ?string = null,\n  ) {\n    const l = blockConfigs.length - 1;\n    for (let i = 0; i <= l; i++) {\n      const config = blockConfigs[i];\n      config.parent = parent;\n      config.prevSibling = i > 0 ? blockConfigs[i - 1].key : null;\n      config.nextSibling = i < l ? blockConfigs[i + 1].key : null;\n      config.children = List(config.childConfigs.map(child => child.key));\n      this.contentBlocks.push(new ContentBlockNode({...config}));\n      this._toContentBlocks(config.childConfigs, config.key);\n    }\n  }\n\n  /**\n   * Remove 'useless' container nodes from the block config hierarchy, by\n   * replacing them with their children.\n   */\n\n  _hoistContainersInBlockConfigs(\n    blockConfigs: Array<ContentBlockConfig>,\n  ): List<ContentBlockConfig> {\n    const hoisted = List(blockConfigs).flatMap(blockConfig => {\n      // Don't mess with useful blocks\n      if (blockConfig.type !== 'unstyled' || blockConfig.text !== '') {\n        return [blockConfig];\n      }\n\n      return this._hoistContainersInBlockConfigs(blockConfig.childConfigs);\n    });\n\n    return hoisted;\n  }\n\n  // ***********************************************************************\n  // The two methods below are used for backward compatibility when\n  // experimentalTreeDataSupport is disabled.\n\n  /**\n   * Same as _toContentBlocks but replaces nested blocks by their\n   * text content.\n   */\n  _toFlatContentBlocks(blockConfigs: Array<ContentBlockConfig>) {\n    const cleanConfigs = this._hoistContainersInBlockConfigs(blockConfigs);\n    cleanConfigs.forEach(config => {\n      const {text, characterList} = this._extractTextFromBlockConfigs(\n        config.childConfigs,\n      );\n      this.contentBlocks.push(\n        new ContentBlock({\n          ...config,\n          text: config.text + text,\n          characterList: config.characterList.concat(characterList),\n        }),\n      );\n    });\n  }\n\n  /**\n   * Extract the text and the associated inline styles form an\n   * array of content block configs.\n   */\n  _extractTextFromBlockConfigs(blockConfigs: Array<ContentBlockConfig>): {\n    text: string,\n    characterList: List<CharacterMetadata>,\n    ...\n  } {\n    const l = blockConfigs.length - 1;\n    let text = '';\n    let characterList = List<CharacterMetadata>();\n    for (let i = 0; i <= l; i++) {\n      const config = blockConfigs[i];\n      text += config.text;\n      characterList = characterList.concat(config.characterList);\n      if (text !== '' && config.type !== 'unstyled') {\n        text += '\\n';\n        characterList = characterList.push(characterList.last());\n      }\n      const children = this._extractTextFromBlockConfigs(config.childConfigs);\n      text += children.text;\n      characterList = characterList.concat(children.characterList);\n    }\n    return {text, characterList};\n  }\n}\n\n/**\n * Converts an HTML string to an array of ContentBlocks and an EntityMap\n * suitable to initialize the internal state of a Draftjs component.\n */\nconst convertFromHTMLToContentBlocks = (\n  html: string,\n  DOMBuilder: Function = getSafeBodyFromHTML,\n  blockRenderMap?: DraftBlockRenderMap = DefaultDraftBlockRenderMap,\n): ?{\n  contentBlocks: ?Array<BlockNodeRecord>,\n  entityMap: EntityMap,\n  ...\n} => {\n  // Be ABSOLUTELY SURE that the dom builder you pass here won't execute\n  // arbitrary code in whatever environment you're running this in. For an\n  // example of how we try to do this in-browser, see getSafeBodyFromHTML.\n\n  // Remove funky characters from the HTML string\n  html = html\n    .trim()\n    .replace(REGEX_CR, '')\n    .replace(REGEX_NBSP, SPACE)\n    .replace(REGEX_CARRIAGE, '')\n    .replace(REGEX_ZWS, '');\n\n  // Build a DOM tree out of the HTML string\n  const safeBody = DOMBuilder(html);\n  if (!safeBody) {\n    return null;\n  }\n\n  // Build a BlockTypeMap out of the BlockRenderMap\n  const blockTypeMap = buildBlockTypeMap(blockRenderMap);\n\n  // Select the proper block type for the cases where the blockRenderMap\n  // uses multiple block types for the same html tag.\n  const disambiguate = (tag: string, wrapper: ?string): ?string => {\n    if (tag === 'li') {\n      return wrapper === 'ol' ? 'ordered-list-item' : 'unordered-list-item';\n    }\n    return null;\n  };\n\n  return new ContentBlocksBuilder(blockTypeMap, disambiguate)\n    .addDOMNode(safeBody)\n    .getContentBlocks();\n};\n\nmodule.exports = convertFromHTMLToContentBlocks;\n"
  },
  {
    "path": "src/model/encoding/convertFromRawToDraftState.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\nimport type {BlockMap} from 'BlockMap';\nimport type {BlockNodeConfig} from 'BlockNode';\nimport type CharacterMetadata from 'CharacterMetadata';\nimport type {DraftBlockType} from 'DraftBlockType';\nimport type {EntityRange} from 'EntityRange';\nimport type {InlineStyleRange} from 'InlineStyleRange';\nimport type {RawDraftContentBlock} from 'RawDraftContentBlock';\nimport type {RawDraftContentState} from 'RawDraftContentState';\n\nconst ContentBlock = require('ContentBlock');\nconst ContentBlockNode = require('ContentBlockNode');\nconst ContentState = require('ContentState');\nconst DraftTreeAdapter = require('DraftTreeAdapter');\nconst DraftTreeInvariants = require('DraftTreeInvariants');\nconst SelectionState = require('SelectionState');\n\nconst createCharacterList = require('createCharacterList');\nconst decodeEntityRanges = require('decodeEntityRanges');\nconst decodeInlineStyleRanges = require('decodeInlineStyleRanges');\nconst generateRandomKey = require('generateRandomKey');\nconst gkx = require('gkx');\nconst Immutable = require('immutable');\nconst invariant = require('invariant');\n\nconst experimentalTreeDataSupport = gkx('draft_tree_data_support');\n\nconst {List, Map, OrderedMap} = Immutable;\n\ntype EntityKeyMap = {[key: number]: number};\n\nconst decodeBlockNodeConfig = (\n  block: RawDraftContentBlock,\n  entityKeyMap: EntityKeyMap,\n): BlockNodeConfig => {\n  const {key, type, data, text, depth} = block;\n\n  const blockNodeConfig: BlockNodeConfig = {\n    text,\n    depth: depth || 0,\n    type: type || 'unstyled',\n    key: key || generateRandomKey(),\n    data: Map(data),\n    characterList: decodeCharacterList(block, entityKeyMap),\n  };\n\n  return blockNodeConfig;\n};\n\nconst decodeCharacterList = (\n  block: RawDraftContentBlock,\n  entityKeyMap: EntityKeyMap,\n): List<CharacterMetadata> => {\n  const {\n    text,\n    entityRanges: rawEntityRanges,\n    inlineStyleRanges: rawInlineStyleRanges,\n  } = block;\n\n  const entityRanges = rawEntityRanges || [];\n  const inlineStyleRanges = rawInlineStyleRanges || [];\n\n  // Translate entity range keys to the DraftEntity map.\n  return createCharacterList(\n    decodeInlineStyleRanges(text, inlineStyleRanges),\n    decodeEntityRanges(\n      text,\n      entityRanges\n        .filter(range => entityKeyMap.hasOwnProperty(range.key))\n        .map(range => ({...range, key: entityKeyMap[range.key]})),\n    ),\n  );\n};\n\nconst addKeyIfMissing = (block: RawDraftContentBlock): RawDraftContentBlock => {\n  return {\n    ...block,\n    key: block.key || generateRandomKey(),\n  };\n};\n\n/**\n * Node stack is responsible to ensure we traverse the tree only once\n * in depth order, while also providing parent refs to inner nodes to\n * construct their links.\n */\nconst updateNodeStack = (\n  stack: Array<\n    | any\n    | {\n        children?: Array<RawDraftContentBlock>,\n        data?: any,\n        depth: ?number,\n        entityRanges: ?Array<EntityRange>,\n        inlineStyleRanges: ?Array<InlineStyleRange>,\n        key: ?string,\n        parentRef: ContentBlockNode,\n        text: string,\n        type: DraftBlockType,\n        ...\n      },\n  >,\n  nodes: Array<any>,\n  parentRef: ContentBlockNode,\n): Array<\n  | any\n  | {\n      children?: Array<RawDraftContentBlock>,\n      data?: any,\n      depth: ?number,\n      entityRanges: ?Array<EntityRange>,\n      inlineStyleRanges: ?Array<InlineStyleRange>,\n      key: ?string,\n      parentRef: ContentBlockNode,\n      text: string,\n      type: DraftBlockType,\n      ...\n    },\n> => {\n  const nodesWithParentRef = nodes.map(block => {\n    return {\n      ...block,\n      parentRef,\n    };\n  });\n\n  // since we pop nodes from the stack we need to insert them in reverse\n  return stack.concat(nodesWithParentRef.reverse());\n};\n\n/**\n * This will build a tree draft content state by creating the node\n * reference links into a single tree walk. Each node has a link\n * reference to \"parent\", \"children\", \"nextSibling\" and \"prevSibling\"\n * blockMap will be created using depth ordering.\n */\nconst decodeContentBlockNodes = (\n  blocks: Array<RawDraftContentBlock>,\n  entityMap: EntityKeyMap,\n): BlockMap => {\n  return (\n    blocks\n      // ensure children have valid keys to enable sibling links\n      .map(addKeyIfMissing)\n      .reduce(\n        (blockMap: BlockMap, block: RawDraftContentBlock, index: number) => {\n          invariant(\n            Array.isArray(block.children),\n            'invalid RawDraftContentBlock can not be converted to ContentBlockNode',\n          );\n\n          // ensure children have valid keys to enable sibling links\n          const children = block.children.map(addKeyIfMissing);\n\n          // root level nodes\n          const contentBlockNode = new ContentBlockNode({\n            ...decodeBlockNodeConfig(block, entityMap),\n            prevSibling: index === 0 ? null : blocks[index - 1].key,\n            nextSibling:\n              index === blocks.length - 1 ? null : blocks[index + 1].key,\n            children: List(children.map((child: any) => child.key)),\n          });\n\n          // push root node to blockMap\n          blockMap = blockMap.set(contentBlockNode.getKey(), contentBlockNode);\n\n          // this stack is used to ensure we visit all nodes respecting depth ordering\n          let stack = updateNodeStack([], children, contentBlockNode);\n\n          // start computing children nodes\n          while (stack.length > 0) {\n            // we pop from the stack and start processing this node\n            const node: any = stack.pop();\n\n            // parentRef already points to a converted ContentBlockNode\n            const parentRef: ContentBlockNode = node.parentRef;\n            const siblings = parentRef.getChildKeys();\n            const index = siblings.indexOf(node.key);\n            const isValidBlock = Array.isArray(node.children);\n\n            if (!isValidBlock) {\n              invariant(\n                isValidBlock,\n                'invalid RawDraftContentBlock can not be converted to ContentBlockNode',\n              );\n              break;\n            }\n\n            // ensure children have valid keys to enable sibling links\n            const children = node.children.map(addKeyIfMissing);\n\n            const contentBlockNode = new ContentBlockNode({\n              ...decodeBlockNodeConfig(node, entityMap),\n              parent: parentRef.getKey(),\n              children: List(children.map((child: any) => child.key)),\n              prevSibling: index === 0 ? null : siblings.get(index - 1),\n              nextSibling:\n                index === siblings.size - 1 ? null : siblings.get(index + 1),\n            });\n\n            // push node to blockMap\n            blockMap = blockMap.set(\n              contentBlockNode.getKey(),\n              contentBlockNode,\n            );\n\n            // this stack is used to ensure we visit all nodes respecting depth ordering\n            stack = updateNodeStack(stack, children, contentBlockNode);\n          }\n\n          return blockMap;\n        },\n        OrderedMap(),\n      )\n  );\n};\n\nconst decodeContentBlocks = (\n  blocks: Array<RawDraftContentBlock>,\n  entityKeyMap: EntityKeyMap,\n): BlockMap => {\n  return OrderedMap(\n    blocks.map((block: RawDraftContentBlock) => {\n      const contentBlock = new ContentBlock(\n        decodeBlockNodeConfig(block, entityKeyMap),\n      );\n      return [contentBlock.getKey(), contentBlock];\n    }),\n  );\n};\n\nconst decodeRawBlocks = (\n  rawState: RawDraftContentState,\n  entityKeyMap: EntityKeyMap,\n): BlockMap => {\n  const isTreeRawBlock = rawState.blocks.find(\n    block => Array.isArray(block.children) && block.children.length > 0,\n  );\n  const rawBlocks =\n    experimentalTreeDataSupport && !isTreeRawBlock\n      ? DraftTreeAdapter.fromRawStateToRawTreeState(rawState).blocks\n      : rawState.blocks;\n\n  if (!experimentalTreeDataSupport) {\n    return decodeContentBlocks(\n      isTreeRawBlock\n        ? DraftTreeAdapter.fromRawTreeStateToRawState(rawState).blocks\n        : rawBlocks,\n      entityKeyMap,\n    );\n  }\n\n  const blockMap = decodeContentBlockNodes(rawBlocks, entityKeyMap);\n  // in dev mode, check that the tree invariants are met\n  if (__DEV__) {\n    invariant(\n      DraftTreeInvariants.isValidTree(blockMap),\n      'Should be a valid tree',\n    );\n  }\n  return blockMap;\n};\n\nconst decodeRawEntityMap = (\n  contentStateArg: ContentState,\n  rawState: RawDraftContentState,\n): {entityKeyMap: EntityKeyMap, contentState: ContentState} => {\n  const {entityMap: rawEntityMap} = rawState;\n  const entityKeyMap: {[string]: string} = {};\n  let contentState = contentStateArg;\n\n  Object.keys(rawEntityMap).forEach(rawEntityKey => {\n    const {type, mutability, data} = rawEntityMap[rawEntityKey];\n    contentState = contentState.createEntity(type, mutability, data || {});\n    // get the key reference to created entity\n    entityKeyMap[rawEntityKey] = contentState.getLastCreatedEntityKey();\n  });\n\n  // $FlowFixMe[incompatible-return]\n  return {entityKeyMap, contentState};\n};\n\nconst convertFromRawToDraftState = (\n  rawState: RawDraftContentState,\n): ContentState => {\n  invariant(Array.isArray(rawState.blocks), 'invalid RawDraftContentState');\n\n  // decode entities\n  const {contentState, entityKeyMap} = decodeRawEntityMap(\n    ContentState.createFromText(''),\n    rawState,\n  );\n\n  // decode blockMap\n  const blockMap = decodeRawBlocks(rawState, entityKeyMap);\n\n  // create initial selection\n  const selectionState = blockMap.isEmpty()\n    ? new SelectionState()\n    : SelectionState.createEmpty(blockMap.first().getKey());\n\n  return new ContentState({\n    blockMap,\n    entityMap: contentState.getEntityMap(),\n    selectionBefore: selectionState,\n    selectionAfter: selectionState,\n  });\n};\n\nmodule.exports = convertFromRawToDraftState;\n"
  },
  {
    "path": "src/model/encoding/createCharacterList.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {DraftInlineStyle} from 'DraftInlineStyle';\n\nconst CharacterMetadata = require('CharacterMetadata');\n\nconst Immutable = require('immutable');\n\nconst {List} = Immutable;\n\nfunction createCharacterList(\n  inlineStyles: Array<DraftInlineStyle>,\n  entities: Array<?string>,\n): List<CharacterMetadata> {\n  const characterArray = inlineStyles.map((style, ii) => {\n    const entity = entities[ii];\n    return CharacterMetadata.create({style, entity});\n  });\n  return List(characterArray);\n}\n\nmodule.exports = createCharacterList;\n"
  },
  {
    "path": "src/model/encoding/decodeEntityRanges.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {EntityRange} from 'EntityRange';\n\nconst UnicodeUtils = require('UnicodeUtils');\n\nconst {substr} = UnicodeUtils;\n\n/**\n * Convert to native JavaScript string lengths to determine ranges.\n */\nfunction decodeEntityRanges(\n  text: string,\n  ranges: Array<EntityRange>,\n): Array<?string> {\n  const entities = Array(text.length).fill(null);\n  if (ranges) {\n    ranges.forEach(range => {\n      // Using Unicode-enabled substrings converted to JavaScript lengths,\n      // fill the output array with entity keys.\n      const start = substr(text, 0, range.offset).length;\n      const end = start + substr(text, range.offset, range.length).length;\n      for (let ii = start; ii < end; ii++) {\n        entities[ii] = range.key;\n      }\n    });\n  }\n  return entities;\n}\n\nmodule.exports = decodeEntityRanges;\n"
  },
  {
    "path": "src/model/encoding/decodeInlineStyleRanges.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {DraftInlineStyle} from 'DraftInlineStyle';\nimport type {InlineStyleRange} from 'InlineStyleRange';\n\nconst UnicodeUtils = require('UnicodeUtils');\n\nconst {OrderedSet} = require('immutable');\nconst {substr} = UnicodeUtils;\n\nconst EMPTY_SET = OrderedSet<mixed>();\n\n/**\n * Convert to native JavaScript string lengths to determine ranges.\n */\nfunction decodeInlineStyleRanges(\n  text: string,\n  ranges?: Array<InlineStyleRange>,\n): Array<DraftInlineStyle> {\n  const styles = Array(text.length).fill(EMPTY_SET);\n  if (ranges) {\n    ranges.forEach(range => {\n      let cursor = substr(text, 0, range.offset).length;\n      const end = cursor + substr(text, range.offset, range.length).length;\n      while (cursor < end) {\n        styles[cursor] = styles[cursor].add(range.style);\n        cursor++;\n      }\n    });\n  }\n  return styles;\n}\n\nmodule.exports = decodeInlineStyleRanges;\n"
  },
  {
    "path": "src/model/encoding/encodeEntityRanges.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type {EntityRange} from 'EntityRange';\n\nconst DraftStringKey = require('DraftStringKey');\nconst UnicodeUtils = require('UnicodeUtils');\n\nconst {strlen} = UnicodeUtils;\n\n/**\n * Convert to UTF-8 character counts for storage.\n */\nfunction encodeEntityRanges(\n  block: BlockNodeRecord,\n  storageMap: Object,\n): Array<EntityRange> {\n  const encoded = [];\n  block.findEntityRanges(\n    character => !!character.getEntity(),\n    (/*number*/ start, /*number*/ end) => {\n      const text = block.getText();\n      const key = block.getEntityAt(start);\n      encoded.push({\n        offset: strlen(text.slice(0, start)),\n        length: strlen(text.slice(start, end)),\n        // Encode the key as a number for range storage.\n        key: Number(storageMap[DraftStringKey.stringify(key)]),\n      });\n    },\n  );\n  return encoded;\n}\n\nmodule.exports = encodeEntityRanges;\n"
  },
  {
    "path": "src/model/encoding/encodeInlineStyleRanges.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type {DraftInlineStyle} from 'DraftInlineStyle';\nimport type {InlineStyleRange} from 'InlineStyleRange';\nimport type {List} from 'immutable';\n\nconst UnicodeUtils = require('UnicodeUtils');\n\nconst findRangesImmutable = require('findRangesImmutable');\n\nconst areEqual = (a: boolean, b: boolean) => a === b;\nconst isTruthy = (a: boolean) => !!a;\nconst EMPTY_ARRAY: Array<$FlowFixMe> = [];\n\n/**\n * Helper function for getting encoded styles for each inline style. Convert\n * to UTF-8 character counts for storage.\n */\nfunction getEncodedInlinesForType(\n  block: BlockNodeRecord,\n  styleList: List<DraftInlineStyle>,\n  styleToEncode: string,\n): Array<InlineStyleRange> {\n  const ranges = [];\n\n  // Obtain an array with ranges for only the specified style.\n  const filteredInlines = styleList\n    .map(style => style.has(styleToEncode))\n    .toList();\n\n  findRangesImmutable(\n    filteredInlines,\n    areEqual,\n    // We only want to keep ranges with nonzero style values.\n    isTruthy,\n    (start, end) => {\n      const text = block.getText();\n      ranges.push({\n        offset: UnicodeUtils.strlen(text.slice(0, start)),\n        length: UnicodeUtils.strlen(text.slice(start, end)),\n        style: styleToEncode,\n      });\n    },\n  );\n\n  return ranges;\n}\n\n/*\n * Retrieve the encoded arrays of inline styles, with each individual style\n * treated separately.\n */\nfunction encodeInlineStyleRanges(\n  block: BlockNodeRecord,\n): Array<InlineStyleRange> {\n  const styleList = block\n    .getCharacterList()\n    .map(c => c.getStyle())\n    .toList();\n  const ranges = styleList\n    .flatten()\n    .toSet()\n    .map(style => getEncodedInlinesForType(block, styleList, style));\n\n  // $FlowFixMe[method-unbinding] added when improving typing for this parameters\n  return Array.prototype.concat.apply(EMPTY_ARRAY, ranges.toJS());\n}\n\nmodule.exports = encodeInlineStyleRanges;\n"
  },
  {
    "path": "src/model/encoding/sanitizeDraftText.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst REGEX_BLOCK_DELIMITER = new RegExp('\\r', 'g');\n\nfunction sanitizeDraftText(input: string): string {\n  return input.replace(REGEX_BLOCK_DELIMITER, '');\n}\n\nmodule.exports = sanitizeDraftText;\n"
  },
  {
    "path": "src/model/entity/DraftEntity.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\nimport type {DraftEntityMutability} from 'DraftEntityMutability';\nimport type {DraftEntityType} from 'DraftEntityType';\n\nconst DraftEntityInstance = require('DraftEntityInstance');\n\nconst Immutable = require('immutable');\nconst invariant = require('invariant');\nconst uuid = require('uuid');\n\nconst {OrderedMap} = Immutable;\n\nlet instances: OrderedMap<string, DraftEntityInstance> = OrderedMap();\nlet instanceKey: string = uuid();\n\nexport type DraftEntityMapObject = {\n  __loadWithEntities: (\n    entities: OrderedMap<string, DraftEntityInstance>,\n  ) => void,\n  __getAll: () => OrderedMap<string, DraftEntityInstance>,\n  __getLastCreatedEntityKey: () => string,\n  __create: (\n    type: DraftEntityType,\n    mutability: DraftEntityMutability,\n    data?: Object,\n  ) => string,\n  __add: (instance: DraftEntityInstance) => string,\n  __get: (key: string) => DraftEntityInstance,\n  __mergeData: (\n    key: string,\n    toMerge: {[key: string]: any, ...},\n  ) => DraftEntityInstance,\n  __replaceData: (\n    key: string,\n    newData: {[key: string]: any, ...},\n  ) => DraftEntityInstance,\n\n  // Temporary public API for gk'd deprecation\n  get: (key: string) => DraftEntityInstance,\n  set: (key: string, value: DraftEntityInstance) => DraftEntityMapObject,\n  last: () => DraftEntityInstance,\n};\n\n/**\n * A \"document entity\" is an object containing metadata associated with a\n * piece of text in a ContentBlock.\n *\n * For example, a `link` entity might include a `uri` property. When a\n * ContentBlock is rendered in the browser, text that refers to that link\n * entity may be rendered as an anchor, with the `uri` as the href value.\n *\n * In a ContentBlock, every position in the text may correspond to zero\n * or one entities. This correspondence is tracked using a key string,\n * generated via DraftEntity.create() and used to obtain entity metadata\n * via DraftEntity.get().\n */\nconst DraftEntity: DraftEntityMapObject = {\n  /**\n   * Get all the entities in the content state.\n   */\n  __getAll(): OrderedMap<string, DraftEntityInstance> {\n    return instances;\n  },\n\n  /**\n   * Load the entity map with the given set of entities.\n   */\n  __loadWithEntities(entities: OrderedMap<string, DraftEntityInstance>): void {\n    instances = entities;\n    instanceKey = uuid();\n  },\n\n  // ***********************************WARNING******************************\n  // --- the above public API will be deprecated in the next version of Draft!\n  // The methods below this line are private - don't call them directly.\n\n  /**\n   * Get the random key string from whatever entity was last created.\n   * We need this to support the new API, as part of transitioning to put Entity\n   * storage in contentState.\n   */\n  __getLastCreatedEntityKey(): string {\n    return instanceKey;\n  },\n\n  /**\n   * Create a DraftEntityInstance and store it for later retrieval.\n   *\n   * A random key string will be generated and returned. This key may\n   * be used to track the entity's usage in a ContentBlock, and for\n   * retrieving data about the entity at render time.\n   */\n  __create(\n    type: DraftEntityType,\n    mutability: DraftEntityMutability,\n    data?: Object,\n  ): string {\n    return DraftEntity.__add(\n      new DraftEntityInstance({type, mutability, data: data || {}}),\n    );\n  },\n\n  /**\n   * Add an existing DraftEntityInstance to the DraftEntity map. This is\n   * useful when restoring instances from the server.\n   */\n  __add(instance: DraftEntityInstance): string {\n    instanceKey = uuid();\n    instances = instances.set(instanceKey, instance);\n    return instanceKey;\n  },\n\n  /**\n   * Retrieve the entity corresponding to the supplied key string.\n   */\n  __get(key: string): DraftEntityInstance {\n    const instance = instances.get(key);\n    invariant(!!instance, 'Unknown DraftEntity key: %s.', key);\n    return instance;\n  },\n\n  get(key: string): DraftEntityInstance {\n    return DraftEntity.__get(key);\n  },\n\n  set(key: string, newInstance: DraftEntityInstance): DraftEntityMapObject {\n    instances = instances.set(key, newInstance);\n    return DraftEntity;\n  },\n\n  last(): DraftEntityInstance {\n    return instances.last();\n  },\n\n  /**\n   * Entity instances are immutable. If you need to update the data for an\n   * instance, this method will merge your data updates and return a new\n   * instance.\n   */\n  __mergeData(\n    key: string,\n    toMerge: {[key: string]: any, ...},\n  ): DraftEntityInstance {\n    const instance = DraftEntity.__get(key);\n    const newData: Object = {...instance.getData(), ...toMerge};\n    const newInstance: DraftEntityInstance = instance.set('data', newData);\n    instances = instances.set(key, newInstance);\n    return newInstance;\n  },\n\n  /**\n   * Completely replace the data for a given instance.\n   */\n  __replaceData(\n    key: string,\n    newData: {[key: string]: any, ...},\n  ): DraftEntityInstance {\n    const instance = DraftEntity.__get(key);\n    const newInstance: DraftEntityInstance = instance.set('data', newData);\n    instances = instances.set(key, newInstance);\n    return newInstance;\n  },\n};\n\nmodule.exports = DraftEntity;\n"
  },
  {
    "path": "src/model/entity/DraftEntityInstance.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @legacyServerCallableInstance\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {DraftEntityMutability} from 'DraftEntityMutability';\nimport type {DraftEntityType} from 'DraftEntityType';\n\nconst Immutable = require('immutable');\n\nconst {Record} = Immutable;\n\nconst DraftEntityInstanceRecord = (Record({\n  type: 'TOKEN',\n  mutability: 'IMMUTABLE',\n  data: Object,\n}): any);\n\n/**\n * An instance of a document entity, consisting of a `type` and relevant\n * `data`, metadata about the entity.\n *\n * For instance, a \"link\" entity might provide a URI, and a \"mention\"\n * entity might provide the mentioned user's ID. These pieces of data\n * may be used when rendering the entity as part of a ContentBlock DOM\n * representation. For a link, the data would be used as an href for\n * the rendered anchor. For a mention, the ID could be used to retrieve\n * a hovercard.\n */\nclass DraftEntityInstance extends DraftEntityInstanceRecord {\n  getType(): DraftEntityType {\n    return this.get('type');\n  }\n\n  getMutability(): DraftEntityMutability {\n    return this.get('mutability');\n  }\n\n  getData(): Object {\n    return this.get('data');\n  }\n}\n\nmodule.exports = DraftEntityInstance;\n"
  },
  {
    "path": "src/model/entity/DraftEntityMutability.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst ComposedEntityMutability = require('ComposedEntityMutability');\n\n/**\n * An enum representing the possible \"mutability\" options for an entity.\n * This refers to the behavior that should occur when inserting or removing\n * characters in a text range with an entity applied to it.\n *\n * `MUTABLE`:\n *   The text range can be modified freely. Generally used in cases where\n *   the text content and the entity do not necessarily have a direct\n *   relationship. For instance, the text and URI for a link may be completely\n *   different. The user is allowed to edit the text as needed, and the entity\n *   is preserved and applied to any characters added within the range.\n *\n * `IMMUTABLE`:\n *   Not to be confused with immutable data structures used to represent the\n *   state of the editor. Immutable entity ranges cannot be modified in any\n *   way. Adding characters within the range will remove the entity from the\n *   entire range. Deleting characters will delete the entire range. Example:\n *   Facebook Page mentions.\n *\n * `SEGMENTED`:\n *   Segmented entities allow the removal of partial ranges of text, as\n *   separated by a delimiter. Adding characters within the range will remove\n *   the entity from the entire range. Deleting characters within a segmented\n *   entity will delete only the segments affected by the deletion. Example:\n *   Facebook User mentions.\n */\n\nexport type DraftEntityMutability = $Keys<typeof ComposedEntityMutability>;\n"
  },
  {
    "path": "src/model/entity/DraftEntityType.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nexport type DraftEntityType = string;\n"
  },
  {
    "path": "src/model/entity/__mocks__/DraftEntity.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @format\n * @oncall draft_js\n */\n\nconst DraftEntity = jest.genMockFromModule('DraftEntity');\n\nconst DraftEntityInstance = {\n  getType: jest.fn(() => ''),\n  getMutability: jest.fn(() => ''),\n  getData: jest.fn(() => ({})),\n};\n\nlet count = 0;\n\nDraftEntity.create = jest.fn(function () {\n  count++;\n  return '' + count;\n});\n\nDraftEntity.get = jest.fn(function () {\n  return DraftEntityInstance;\n});\n\nmodule.exports = DraftEntity;\n"
  },
  {
    "path": "src/model/entity/__tests__/DraftEntity-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst ContentState = require('ContentState');\n\nbeforeEach(() => {\n  jest.resetModules();\n});\n\nconst createLink = (contentState: ContentState) => {\n  const newContentState = contentState.createEntity('LINK', 'MUTABLE', {\n    uri: 'zombo.com',\n  });\n  return {\n    contentState: newContentState,\n    key: contentState.getLastCreatedEntityKey(),\n  };\n};\n\ntest('must create instances', () => {\n  const {key} = createLink(ContentState.createFromText(''));\n  expect(typeof key).toMatchSnapshot();\n});\n\ntest('must retrieve an instance given a key', () => {\n  const {key, contentState} = createLink(ContentState.createFromText(''));\n  const retrieved = contentState.getEntity(key);\n  expect(retrieved.getType()).toMatchSnapshot();\n  expect(retrieved.getMutability()).toMatchSnapshot();\n  expect(retrieved.getData()).toMatchSnapshot();\n});\n\ntest('must throw when retrieving for an invalid key', () => {\n  const {contentState} = createLink(ContentState.createFromText(''));\n  expect(() => contentState.getEntity('asdfzxcvqweriuop')).toThrow();\n});\n\ntest('must merge data', () => {\n  const result = createLink(ContentState.createFromText(''));\n  const key = result.key;\n  let contentState = result.contentState;\n\n  // Merge new property.\n  const newData = {foo: 'bar'};\n  contentState = contentState.mergeEntityData(key, newData);\n  const newEntity = contentState.getEntity(key);\n\n  // Replace existing property.\n  const withNewURI = {uri: 'homestarrunner.com'};\n  contentState = contentState.mergeEntityData(key, withNewURI);\n  const entityWithNewURI = contentState.getEntity(key);\n\n  expect(newEntity.getData()).toMatchSnapshot();\n  expect(entityWithNewURI.getData()).toMatchSnapshot();\n});\n"
  },
  {
    "path": "src/model/entity/__tests__/__snapshots__/DraftEntity-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must create instances 1`] = `\"string\"`;\n\nexports[`must merge data 1`] = `\nObject {\n  \"foo\": \"bar\",\n  \"uri\": \"zombo.com\",\n}\n`;\n\nexports[`must merge data 2`] = `\nObject {\n  \"foo\": \"bar\",\n  \"uri\": \"homestarrunner.com\",\n}\n`;\n\nexports[`must retrieve an instance given a key 1`] = `\"LINK\"`;\n\nexports[`must retrieve an instance given a key 2`] = `\"MUTABLE\"`;\n\nexports[`must retrieve an instance given a key 3`] = `\nObject {\n  \"uri\": \"zombo.com\",\n}\n`;\n"
  },
  {
    "path": "src/model/entity/__tests__/__snapshots__/getEntityKeyForSelection-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must not return key if immutable 1`] = `null`;\n\nexports[`must not return key if immutable with collapsed selection 1`] = `null`;\n\nexports[`must not return key if mutable with collapsed selection at end of an entity 1`] = `null`;\n\nexports[`must not return key if segmented 1`] = `null`;\n\nexports[`must not return key if segmented with collapsed selection 1`] = `null`;\n\nexports[`must return key if mutable 1`] = `\"2\"`;\n\nexports[`must return key if mutable with collapsed selection 1`] = `\"2\"`;\n\nexports[`must return null at start of block with collapsed selection 1`] = `null`;\n\nexports[`must return null if start is at end of block 1`] = `null`;\n"
  },
  {
    "path": "src/model/entity/__tests__/getEntityKeyForSelection-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\nconst getEntityKeyForSelection = require('getEntityKeyForSelection');\nconst getSampleStateForTesting = require('getSampleStateForTesting');\n\nconst {contentState, selectionState} = getSampleStateForTesting();\n\nconst initialSelectionState = selectionState.merge({\n  anchorKey: 'b',\n  focusKey: 'b',\n});\n\nconst COLLAPSED_SELECTION = initialSelectionState.merge({\n  anchorOffset: 2,\n  focusOffset: 2,\n});\n\nconst COLLAPSED_SELECTION_ENTITY_END = initialSelectionState.merge({\n  anchorOffset: 5,\n  focusOffset: 5,\n});\n\nconst NON_COLLAPSED_SELECTION = initialSelectionState.merge({\n  anchorOffset: 2,\n  focusKey: 'c',\n  focusOffset: 2,\n});\n\nconst setEntityMutability = (\n  mutability:\n    | $TEMPORARY$string<'IMMUTABLE'>\n    | $TEMPORARY$string<'MUTABLE'>\n    | $TEMPORARY$string<'SEGMENTED'>,\n) => {\n  // $FlowFixMe error encountered when strong-typing ContentState.getEntityMap\n  contentState.getEntityMap().__get = () => ({\n    getMutability: () => mutability,\n  });\n};\n\ntest('must return null at start of block with collapsed selection', () => {\n  const key = getEntityKeyForSelection(contentState, initialSelectionState);\n  expect(key).toMatchSnapshot();\n});\n\ntest('must return key if mutable with collapsed selection', () => {\n  setEntityMutability('MUTABLE');\n  const key = getEntityKeyForSelection(contentState, COLLAPSED_SELECTION);\n  expect(key).toMatchSnapshot();\n});\n\ntest('must not return key if mutable with collapsed selection at end of an entity', () => {\n  setEntityMutability('MUTABLE');\n  const key = getEntityKeyForSelection(\n    contentState,\n    COLLAPSED_SELECTION_ENTITY_END,\n  );\n  expect(key).toMatchSnapshot();\n});\n\ntest('must not return key if immutable with collapsed selection', () => {\n  setEntityMutability('IMMUTABLE');\n  const key = getEntityKeyForSelection(contentState, COLLAPSED_SELECTION);\n  expect(key).toMatchSnapshot();\n});\n\ntest('must not return key if segmented with collapsed selection', () => {\n  setEntityMutability('SEGMENTED');\n  const key = getEntityKeyForSelection(contentState, COLLAPSED_SELECTION);\n  expect(key).toMatchSnapshot();\n});\n\ntest('must return null if start is at end of block', () => {\n  const startsAtEnd = NON_COLLAPSED_SELECTION.merge({\n    anchorOffset: contentState.getBlockForKey('b').getLength(),\n  });\n  const key = getEntityKeyForSelection(contentState, startsAtEnd);\n  expect(key).toMatchSnapshot();\n});\n\ntest('must return key if mutable', () => {\n  setEntityMutability('MUTABLE');\n  const key = getEntityKeyForSelection(contentState, NON_COLLAPSED_SELECTION);\n  expect(key).toMatchSnapshot();\n});\n\ntest('must not return key if immutable', () => {\n  setEntityMutability('IMMUTABLE');\n  const key = getEntityKeyForSelection(contentState, NON_COLLAPSED_SELECTION);\n  expect(key).toMatchSnapshot();\n});\n\ntest('must not return key if segmented', () => {\n  setEntityMutability('SEGMENTED');\n  const key = getEntityKeyForSelection(contentState, NON_COLLAPSED_SELECTION);\n  expect(key).toMatchSnapshot();\n});\n"
  },
  {
    "path": "src/model/entity/getEntityKeyForSelection.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type ContentState from 'ContentState';\nimport type SelectionState from 'SelectionState';\n\nconst {notEmptyKey} = require('draftKeyUtils');\n\n/**\n * Return the entity key that should be used when inserting text for the\n * specified target selection, only if the entity is `MUTABLE`. `IMMUTABLE`\n * and `SEGMENTED` entities should not be used for insertion behavior.\n */\nfunction getEntityKeyForSelection(\n  contentState: ContentState,\n  targetSelection: SelectionState,\n): ?string {\n  let entityKey;\n\n  if (targetSelection.isCollapsed()) {\n    const key = targetSelection.getAnchorKey();\n    const offset = targetSelection.getAnchorOffset();\n    if (offset > 0) {\n      entityKey = contentState.getBlockForKey(key).getEntityAt(offset - 1);\n      if (entityKey !== contentState.getBlockForKey(key).getEntityAt(offset)) {\n        return null;\n      }\n      return filterKey(contentState, entityKey);\n    }\n    return null;\n  }\n\n  const startKey = targetSelection.getStartKey();\n  const startOffset = targetSelection.getStartOffset();\n  const startBlock = contentState.getBlockForKey(startKey);\n\n  entityKey =\n    startOffset === startBlock.getLength()\n      ? null\n      : startBlock.getEntityAt(startOffset);\n\n  return filterKey(contentState, entityKey);\n}\n\n/**\n * Determine whether an entity key corresponds to a `MUTABLE` entity. If so,\n * return it. If not, return null.\n */\nfunction filterKey(contentState: ContentState, entityKey: ?string): ?string {\n  if (notEmptyKey(entityKey)) {\n    const entity = contentState.getEntity(entityKey);\n    return entity.getMutability() === 'MUTABLE' ? entityKey : null;\n  }\n  return null;\n}\n\nmodule.exports = getEntityKeyForSelection;\n"
  },
  {
    "path": "src/model/entity/getTextAfterNearestEntity.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\n\n/**\n * Find the string of text between the previous entity and the specified\n * offset. This allows us to narrow down search areas for regex matching.\n */\nfunction getTextAfterNearestEntity(\n  block: BlockNodeRecord,\n  offset: number,\n): string {\n  let start = offset;\n\n  // Get start based on where the last entity ended.\n  while (start > 0 && block.getEntityAt(start - 1) === null) {\n    start--;\n  }\n\n  return block.getText().slice(start, offset);\n}\n\nmodule.exports = getTextAfterNearestEntity;\n"
  },
  {
    "path": "src/model/immutable/BlockMap.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type {OrderedMap} from 'immutable';\n\nexport type BlockMap = OrderedMap<string, BlockNodeRecord>;\n"
  },
  {
    "path": "src/model/immutable/BlockMapBuilder.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockMap} from 'BlockMap';\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\n\nconst Immutable = require('immutable');\n\nconst {OrderedMap} = Immutable;\n\nconst BlockMapBuilder = {\n  createFromArray(blocks: Array<BlockNodeRecord>): BlockMap {\n    return OrderedMap(blocks.map(block => [block.getKey(), block]));\n  },\n};\n\nmodule.exports = BlockMapBuilder;\n"
  },
  {
    "path": "src/model/immutable/BlockNode.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type CharacterMetadata, {\n  CharacterMetadataRawConfig,\n} from 'CharacterMetadata';\nimport type {DraftBlockType} from 'DraftBlockType';\nimport type {DraftInlineStyle} from 'DraftInlineStyle';\nimport type {List, Map} from 'immutable';\n\nexport type BlockNodeKey = string;\n\nexport type BlockNodeRawConfig = {\n  characterList?: Array<CharacterMetadataRawConfig>,\n  data?: Map<any, any>,\n  depth?: number,\n  key?: BlockNodeKey,\n  text?: string,\n  type?: DraftBlockType,\n  ...\n};\n\nexport type BlockNodeConfig = {\n  characterList?: List<CharacterMetadata>,\n  data?: Map<any, any>,\n  depth?: number,\n  key?: BlockNodeKey,\n  text?: string,\n  type?: DraftBlockType,\n  ...\n};\n\n// https://github.com/facebook/draft-js/issues/1492\n// prettier-ignore\nexport interface BlockNode {\n  +findEntityRanges: (\n    filterFn: (value: CharacterMetadata) => boolean,\n    callback: (start: number, end: number) => void,\n  ) => void,\n\n  +findStyleRanges: (\n    filterFn: (value: CharacterMetadata) => boolean,\n    callback: (start: number, end: number) => void,\n  ) => void,\n\n  +getCharacterList: () => List<CharacterMetadata>,\n\n  +getData: () => Map<any, any>,\n\n  +getDepth: () => number,\n\n  +getEntityAt: (offset: number) => ?string,\n\n  +getInlineStyleAt: (offset: number) => DraftInlineStyle,\n\n  +getKey: () => BlockNodeKey,\n\n  +getLength: () => number,\n\n  +getText: () => string,\n\n  +getType: () => DraftBlockType,\n}\n"
  },
  {
    "path": "src/model/immutable/BlockNodeRecord.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type ContentBlock from 'ContentBlock';\nimport type ContentBlockNode from 'ContentBlockNode';\n\nexport type BlockNodeRecord = ContentBlock | ContentBlockNode;\n"
  },
  {
    "path": "src/model/immutable/BlockTree.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type CharacterMetadata from 'CharacterMetadata';\nimport type ContentState from 'ContentState';\nimport type {DraftDecoratorType} from 'DraftDecoratorType';\n\nconst findRangesImmutable = require('findRangesImmutable');\nconst getOwnObjectValues = require('getOwnObjectValues');\nconst Immutable = require('immutable');\n\nconst {List, Repeat, Record} = Immutable;\n\nconst returnTrue = function () {\n  return true;\n};\n\nconst defaultLeafRange: {\n  start: ?number,\n  end: ?number,\n  ...\n} = {\n  start: null,\n  end: null,\n};\n\nconst LeafRange = (Record(defaultLeafRange): any);\n\nexport type DecoratorRangeRawType = {\n  start: ?number,\n  end: ?number,\n  decoratorKey: ?string,\n  // $FlowFixMe[value-as-type]\n  leaves: ?Array<LeafRange>,\n  ...\n};\n\ntype DecoratorRangeType = {\n  start: ?number,\n  end: ?number,\n  decoratorKey: ?string,\n  // $FlowFixMe[value-as-type]\n  leaves: ?List<LeafRange>,\n  ...\n};\n\nconst defaultDecoratorRange: DecoratorRangeType = {\n  start: null,\n  end: null,\n  decoratorKey: null,\n  leaves: null,\n};\n\nconst DecoratorRange = (Record(defaultDecoratorRange): any);\n\nconst BlockTree = {\n  /**\n   * Generate a block tree for a given ContentBlock/decorator pair.\n   */\n  generate(\n    contentState: ContentState,\n    block: BlockNodeRecord,\n    decorator: ?DraftDecoratorType,\n    // $FlowFixMe[value-as-type]\n  ): List<DecoratorRange> {\n    const textLength = block.getLength();\n    if (!textLength) {\n      return List.of(\n        new DecoratorRange({\n          start: 0,\n          end: 0,\n          decoratorKey: null,\n          leaves: List.of(new LeafRange({start: 0, end: 0})),\n        }),\n      );\n    }\n\n    const leafSets = [];\n    const decorations = decorator\n      ? decorator.getDecorations(block, contentState)\n      : List(Repeat(null, textLength));\n\n    const chars = block.getCharacterList();\n\n    findRangesImmutable(decorations, areEqual, returnTrue, (start, end) => {\n      leafSets.push(\n        new DecoratorRange({\n          start,\n          end,\n          decoratorKey: decorations.get(start),\n          leaves: generateLeaves(chars.slice(start, end).toList(), start),\n        }),\n      );\n    });\n\n    return List(leafSets);\n  },\n\n  // $FlowFixMe[value-as-type]\n  fromJS({leaves, ...other}: DecoratorRangeRawType): DecoratorRange {\n    return new DecoratorRange({\n      ...other,\n      leaves:\n        leaves != null\n          ? List(\n              Array.isArray(leaves) ? leaves : getOwnObjectValues(leaves),\n            ).map(leaf => LeafRange(leaf))\n          : null,\n    });\n  },\n};\n\n/**\n * Generate LeafRange records for a given character list.\n */\nfunction generateLeaves(\n  characters: List<CharacterMetadata>,\n  offset: number,\n  // $FlowFixMe[value-as-type]\n): List<LeafRange> {\n  const leaves = [];\n  const inlineStyles = characters.map(c => c.getStyle()).toList();\n  findRangesImmutable(inlineStyles, areEqual, returnTrue, (start, end) => {\n    leaves.push(\n      new LeafRange({\n        start: start + offset,\n        end: end + offset,\n      }),\n    );\n  });\n  return List(leaves);\n}\n\nfunction areEqual(a: any, b: any): boolean {\n  return a === b;\n}\n\nmodule.exports = BlockTree;\n"
  },
  {
    "path": "src/model/immutable/CharacterMetadata.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {DraftInlineStyle} from 'DraftInlineStyle';\n\nconst {Map, OrderedSet, Record} = require('immutable');\n\n// Immutable.map is typed such that the value for every key in the map\n// must be the same type\ntype CharacterMetadataConfigValueType = DraftInlineStyle | ?string;\ntype CharacterMetadataConfigRawValueType = Array<string> | ?string;\n\nexport type CharacterMetadataRawConfig = {\n  style?: CharacterMetadataConfigRawValueType,\n  entity?: CharacterMetadataConfigRawValueType,\n  ...\n};\n\ntype CharacterMetadataConfig = interface {\n  style?: CharacterMetadataConfigValueType,\n  entity?: CharacterMetadataConfigValueType,\n};\n\nconst EMPTY_SET = OrderedSet<string>();\n\nconst defaultRecord: CharacterMetadataConfig = {\n  style: EMPTY_SET,\n  entity: null,\n};\n\nconst CharacterMetadataRecord = (Record(defaultRecord): any);\n\nclass CharacterMetadata extends CharacterMetadataRecord {\n  getStyle(): DraftInlineStyle {\n    return this.get('style');\n  }\n\n  getEntity(): ?string {\n    return this.get('entity');\n  }\n\n  hasStyle(style: string): boolean {\n    return this.getStyle().includes(style);\n  }\n\n  static applyStyle(\n    record: CharacterMetadata,\n    style: string,\n  ): CharacterMetadata {\n    const withStyle = record.set('style', record.getStyle().add(style));\n    return CharacterMetadata.create(withStyle);\n  }\n\n  static removeStyle(\n    record: CharacterMetadata,\n    style: string,\n  ): CharacterMetadata {\n    const withoutStyle = record.set('style', record.getStyle().remove(style));\n    return CharacterMetadata.create(withoutStyle);\n  }\n\n  static applyEntity(\n    record: CharacterMetadata,\n    entityKey: ?string,\n  ): CharacterMetadata {\n    const withEntity =\n      record.getEntity() === entityKey\n        ? record\n        : record.set('entity', entityKey);\n    return CharacterMetadata.create(withEntity);\n  }\n\n  /**\n   * Use this function instead of the `CharacterMetadata` constructor.\n   * Since most content generally uses only a very small number of\n   * style/entity permutations, we can reuse these objects as often as\n   * possible.\n   */\n  static create(config?: CharacterMetadataConfig): CharacterMetadata {\n    if (!config) {\n      return EMPTY;\n    }\n\n    const defaultConfig: CharacterMetadataConfig = {\n      style: EMPTY_SET,\n      entity: (null: ?string),\n    };\n\n    // Fill in unspecified properties, if necessary.\n    // $FlowFixMe[incompatible-call] added when improving typing for this parameters\n    const configMap = Map(defaultConfig).merge(config);\n\n    const existing: ?CharacterMetadata = pool.get(configMap);\n    if (existing) {\n      return existing;\n    }\n\n    const newCharacter = new CharacterMetadata(configMap);\n    pool = pool.set(configMap, newCharacter);\n    return newCharacter;\n  }\n\n  static fromJS({\n    style,\n    entity,\n  }: CharacterMetadataRawConfig): CharacterMetadata {\n    return new CharacterMetadata({\n      style: Array.isArray(style) ? OrderedSet(style) : style,\n      entity: Array.isArray(entity) ? OrderedSet(entity) : entity,\n    });\n  }\n}\n\nconst EMPTY = new CharacterMetadata();\nlet pool: Map<Map<any, any>, CharacterMetadata> = Map([\n  // $FlowFixMe[incompatible-call] added when improving typing for this parameters\n  [Map(defaultRecord), EMPTY],\n]);\n\nCharacterMetadata.EMPTY = EMPTY;\n\nmodule.exports = CharacterMetadata;\n"
  },
  {
    "path": "src/model/immutable/ContentBlock.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNode, BlockNodeConfig, BlockNodeKey} from 'BlockNode';\nimport type {DraftBlockType} from 'DraftBlockType';\nimport type {DraftInlineStyle} from 'DraftInlineStyle';\n\nconst CharacterMetadata = require('CharacterMetadata');\n\nconst findRangesImmutable = require('findRangesImmutable');\nconst Immutable = require('immutable');\n\nconst {List, Map, OrderedSet, Record, Repeat} = Immutable;\n\nconst EMPTY_SET = OrderedSet<string>();\n\nconst defaultRecord: BlockNodeConfig = {\n  key: '',\n  type: 'unstyled',\n  text: '',\n  characterList: List(),\n  depth: 0,\n  data: Map(),\n};\n\nconst ContentBlockRecord = (Record(defaultRecord): any);\n\nconst decorateCharacterList = (config: BlockNodeConfig): BlockNodeConfig => {\n  if (!config) {\n    return config;\n  }\n\n  const {characterList, text} = config;\n\n  if (text && !characterList) {\n    config.characterList = List(Repeat(CharacterMetadata.EMPTY, text.length));\n  }\n\n  return config;\n};\n\nclass ContentBlock extends ContentBlockRecord implements BlockNode {\n  constructor(config: BlockNodeConfig) {\n    super(decorateCharacterList(config));\n  }\n\n  // $FlowFixMe[method-unbinding]\n  getKey(): BlockNodeKey {\n    return this.get('key');\n  }\n\n  // $FlowFixMe[method-unbinding]\n  getType(): DraftBlockType {\n    return this.get('type');\n  }\n\n  // $FlowFixMe[method-unbinding]\n  getText(): string {\n    return this.get('text');\n  }\n\n  // $FlowFixMe[method-unbinding]\n  getCharacterList(): List<CharacterMetadata> {\n    return this.get('characterList');\n  }\n\n  // $FlowFixMe[method-unbinding]\n  getLength(): number {\n    return this.getText().length;\n  }\n\n  // $FlowFixMe[method-unbinding]\n  getDepth(): number {\n    return this.get('depth');\n  }\n\n  // $FlowFixMe[method-unbinding]\n  getData(): Map<any, any> {\n    return this.get('data');\n  }\n\n  // $FlowFixMe[method-unbinding]\n  getInlineStyleAt(offset: number): DraftInlineStyle {\n    const character = this.getCharacterList().get(offset);\n    return character ? character.getStyle() : EMPTY_SET;\n  }\n\n  // $FlowFixMe[method-unbinding]\n  getEntityAt(offset: number): ?string {\n    const character = this.getCharacterList().get(offset);\n    return character ? character.getEntity() : null;\n  }\n\n  /**\n   * Execute a callback for every contiguous range of styles within the block.\n   */\n  // $FlowFixMe[method-unbinding]\n  findStyleRanges(\n    filterFn: (value: CharacterMetadata) => boolean,\n    callback: (start: number, end: number) => void,\n  ): void {\n    findRangesImmutable(\n      this.getCharacterList(),\n      haveEqualStyle,\n      filterFn,\n      callback,\n    );\n  }\n\n  /**\n   * Execute a callback for every contiguous range of entities within the block.\n   */\n  // $FlowFixMe[method-unbinding]\n  findEntityRanges(\n    filterFn: (value: CharacterMetadata) => boolean,\n    callback: (start: number, end: number) => void,\n  ): void {\n    findRangesImmutable(\n      this.getCharacterList(),\n      haveEqualEntity,\n      filterFn,\n      callback,\n    );\n  }\n}\n\nfunction haveEqualStyle(\n  charA: CharacterMetadata,\n  charB: CharacterMetadata,\n): boolean {\n  return charA.getStyle() === charB.getStyle();\n}\n\nfunction haveEqualEntity(\n  charA: CharacterMetadata,\n  charB: CharacterMetadata,\n): boolean {\n  return charA.getEntity() === charB.getEntity();\n}\n\nmodule.exports = ContentBlock;\n"
  },
  {
    "path": "src/model/immutable/ContentBlockNode.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * This file is a fork of ContentBlock adding support for nesting references by\n * providing links to children, parent, prevSibling, and nextSibling.\n *\n * This is unstable and not part of the public API and should not be used by\n * production systems. This file may be update/removed without notice.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNode, BlockNodeConfig, BlockNodeKey} from 'BlockNode';\nimport type {DraftBlockType} from 'DraftBlockType';\nimport type {DraftInlineStyle} from 'DraftInlineStyle';\n\nconst CharacterMetadata = require('CharacterMetadata');\n\nconst findRangesImmutable = require('findRangesImmutable');\nconst Immutable = require('immutable');\n\nconst {List, Map, OrderedSet, Record, Repeat} = Immutable;\n\ntype ContentBlockNodeConfig = BlockNodeConfig & {\n  children?: List<BlockNodeKey>,\n  parent?: ?BlockNodeKey,\n  prevSibling?: ?BlockNodeKey,\n  nextSibling?: ?BlockNodeKey,\n  ...\n};\n\nconst EMPTY_SET = OrderedSet<string>();\n\nconst defaultRecord: ContentBlockNodeConfig = {\n  parent: null,\n  characterList: List(),\n  data: Map(),\n  depth: 0,\n  key: '',\n  text: '',\n  type: 'unstyled',\n  children: List(),\n  prevSibling: null,\n  nextSibling: null,\n};\n\nconst haveEqualStyle = (\n  charA: CharacterMetadata,\n  charB: CharacterMetadata,\n): boolean => charA.getStyle() === charB.getStyle();\n\nconst haveEqualEntity = (\n  charA: CharacterMetadata,\n  charB: CharacterMetadata,\n): boolean => charA.getEntity() === charB.getEntity();\n\nconst decorateCharacterList = (\n  config: ContentBlockNodeConfig,\n): ContentBlockNodeConfig => {\n  if (!config) {\n    return config;\n  }\n\n  const {characterList, text} = config;\n\n  if (text && !characterList) {\n    config.characterList = List(Repeat(CharacterMetadata.EMPTY, text.length));\n  }\n\n  return config;\n};\n\nclass ContentBlockNode\n  extends (Record(defaultRecord): any)\n  implements BlockNode\n{\n  constructor(props: ContentBlockNodeConfig = defaultRecord) {\n    /* eslint-disable-next-line constructor-super */\n    super(decorateCharacterList(props));\n  }\n\n  // $FlowFixMe[method-unbinding]\n  getKey(): BlockNodeKey {\n    return this.get('key');\n  }\n\n  // $FlowFixMe[method-unbinding]\n  getType(): DraftBlockType {\n    return this.get('type');\n  }\n\n  // $FlowFixMe[method-unbinding]\n  getText(): string {\n    return this.get('text');\n  }\n\n  // $FlowFixMe[method-unbinding]\n  getCharacterList(): List<CharacterMetadata> {\n    return this.get('characterList');\n  }\n\n  // $FlowFixMe[method-unbinding]\n  getLength(): number {\n    return this.getText().length;\n  }\n\n  // $FlowFixMe[method-unbinding]\n  getDepth(): number {\n    return this.get('depth');\n  }\n\n  // $FlowFixMe[method-unbinding]\n  getData(): Map<any, any> {\n    return this.get('data');\n  }\n\n  // $FlowFixMe[method-unbinding]\n  getInlineStyleAt(offset: number): DraftInlineStyle {\n    const character = this.getCharacterList().get(offset);\n    return character ? character.getStyle() : EMPTY_SET;\n  }\n\n  // $FlowFixMe[method-unbinding]\n  getEntityAt(offset: number): ?string {\n    const character = this.getCharacterList().get(offset);\n    return character ? character.getEntity() : null;\n  }\n\n  getChildKeys(): List<BlockNodeKey> {\n    return this.get('children');\n  }\n\n  getParentKey(): ?BlockNodeKey {\n    return this.get('parent');\n  }\n\n  getPrevSiblingKey(): ?BlockNodeKey {\n    return this.get('prevSibling');\n  }\n\n  getNextSiblingKey(): ?BlockNodeKey {\n    return this.get('nextSibling');\n  }\n\n  // $FlowFixMe[method-unbinding]\n  findStyleRanges(\n    filterFn: (value: CharacterMetadata) => boolean,\n    callback: (start: number, end: number) => void,\n  ): void {\n    findRangesImmutable(\n      this.getCharacterList(),\n      haveEqualStyle,\n      filterFn,\n      callback,\n    );\n  }\n\n  // $FlowFixMe[method-unbinding]\n  findEntityRanges(\n    filterFn: (value: CharacterMetadata) => boolean,\n    callback: (start: number, end: number) => void,\n  ): void {\n    findRangesImmutable(\n      this.getCharacterList(),\n      haveEqualEntity,\n      filterFn,\n      callback,\n    );\n  }\n}\n\nmodule.exports = ContentBlockNode;\n"
  },
  {
    "path": "src/model/immutable/ContentState.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockMap} from 'BlockMap';\nimport type {BlockNodeRawConfig} from 'BlockNode';\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type {ContentStateRawType} from 'ContentStateRawType';\nimport type DraftEntityInstance from 'DraftEntityInstance';\nimport type {DraftEntityMutability} from 'DraftEntityMutability';\nimport type {DraftEntityType} from 'DraftEntityType';\nimport type {EntityMap} from 'EntityMap';\n\nconst BlockMapBuilder = require('BlockMapBuilder');\nconst CharacterMetadata = require('CharacterMetadata');\nconst ContentBlock = require('ContentBlock');\nconst ContentBlockNode = require('ContentBlockNode');\nconst DraftEntity = require('DraftEntity');\nconst SelectionState = require('SelectionState');\n\nconst generateRandomKey = require('generateRandomKey');\nconst getOwnObjectValues = require('getOwnObjectValues');\nconst gkx = require('gkx');\nconst Immutable = require('immutable');\nconst sanitizeDraftText = require('sanitizeDraftText');\n\nconst {List, Record, Repeat, Map: ImmutableMap, OrderedMap} = Immutable;\n\ntype ContentStateRecordType = {\n  entityMap: ?any,\n  blockMap: ?BlockMap,\n  selectionBefore: ?SelectionState,\n  selectionAfter: ?SelectionState,\n  ...\n};\n\nconst defaultRecord: ContentStateRecordType = {\n  entityMap: null,\n  blockMap: null,\n  selectionBefore: null,\n  selectionAfter: null,\n};\n\n// Immutable 3 typedefs are not good, so ContentState ends up\n// subclassing `any`. Define a rudimentary type for the\n// supercalss here instead.\ndeclare class ContentStateRecordHelper {\n  constructor(args: any): ContentState;\n  merge(args: any): any;\n  setIn(keyPath: Array<string>, value: any): ContentState;\n  equals(other: ContentState): boolean;\n  mergeDeep(other: any): ContentState;\n}\n\nconst ContentStateRecord: typeof ContentStateRecordHelper = (Record(\n  defaultRecord,\n): any);\n\n/* $FlowFixMe[signature-verification-failure] Supressing a `signature-\n * verification-failure` error here. TODO: T65949050 Clean up the branch for\n * this GK */\nconst ContentBlockNodeRecord = gkx('draft_tree_data_support')\n  ? ContentBlockNode\n  : ContentBlock;\n\nclass ContentState extends ContentStateRecord {\n  getEntityMap(): EntityMap {\n    // TODO: update this when we fully remove DraftEntity\n    return DraftEntity;\n  }\n\n  getBlockMap(): BlockMap {\n    // $FlowFixMe[prop-missing] found when removing casts of this to any\n    return this.get('blockMap');\n  }\n\n  getSelectionBefore(): SelectionState {\n    // $FlowFixMe[prop-missing] found when removing casts of this to any\n    return this.get('selectionBefore');\n  }\n\n  getSelectionAfter(): SelectionState {\n    // $FlowFixMe[prop-missing] found when removing casts of this to any\n    return this.get('selectionAfter');\n  }\n\n  getBlockForKey(key: string): BlockNodeRecord {\n    const block: BlockNodeRecord = this.getBlockMap().get(key);\n    return block;\n  }\n\n  getKeyBefore(key: string): ?string {\n    return this.getBlockMap()\n      .reverse()\n      .keySeq()\n      .skipUntil(v => v === key)\n      .skip(1)\n      .first();\n  }\n\n  getKeyAfter(key: string): ?string {\n    return this.getBlockMap()\n      .keySeq()\n      .skipUntil(v => v === key)\n      .skip(1)\n      .first();\n  }\n\n  getBlockAfter(key: string): ?BlockNodeRecord {\n    return this.getBlockMap()\n      .skipUntil((_, k) => k === key)\n      .skip(1)\n      .first();\n  }\n\n  getBlockBefore(key: string): ?BlockNodeRecord {\n    return this.getBlockMap()\n      .reverse()\n      .skipUntil((_, k) => k === key)\n      .skip(1)\n      .first();\n  }\n\n  getBlocksAsArray(): Array<BlockNodeRecord> {\n    return this.getBlockMap().toArray();\n  }\n\n  getFirstBlock(): BlockNodeRecord {\n    return this.getBlockMap().first();\n  }\n\n  getLastBlock(): BlockNodeRecord {\n    return this.getBlockMap().last();\n  }\n\n  getPlainText(delimiter?: string): string {\n    return this.getBlockMap()\n      .map(block => {\n        return block ? block.getText() : '';\n      })\n      .join(delimiter || '\\n');\n  }\n\n  getLastCreatedEntityKey(): string {\n    // TODO: update this when we fully remove DraftEntity\n    return DraftEntity.__getLastCreatedEntityKey();\n  }\n\n  hasText(): boolean {\n    const blockMap = this.getBlockMap();\n    return (\n      blockMap.size > 1 ||\n      // make sure that there are no zero width space chars\n      escape(blockMap.first().getText()).replace(/%u200B/g, '').length > 0\n    );\n  }\n\n  createEntity(\n    type: DraftEntityType,\n    mutability: DraftEntityMutability,\n    data?: Object,\n  ): ContentState {\n    // TODO: update this when we fully remove DraftEntity\n    DraftEntity.__create(type, mutability, data);\n    return this;\n  }\n\n  mergeEntityData(\n    key: string,\n    toMerge: {[key: string]: any, ...},\n  ): ContentState {\n    // TODO: update this when we fully remove DraftEntity\n    DraftEntity.__mergeData(key, toMerge);\n    return this;\n  }\n\n  replaceEntityData(\n    key: string,\n    newData: interface {[key: string]: any},\n  ): ContentState {\n    // TODO: update this when we fully remove DraftEntity\n    /* $FlowFixMe[class-object-subtyping] added when improving typing for this\n     * parameters */\n    DraftEntity.__replaceData(key, newData);\n    return this;\n  }\n\n  addEntity(instance: DraftEntityInstance): ContentState {\n    // TODO: update this when we fully remove DraftEntity\n    DraftEntity.__add(instance);\n    return this;\n  }\n\n  getEntity(key: string): DraftEntityInstance {\n    // TODO: update this when we fully remove DraftEntity\n    return DraftEntity.__get(key);\n  }\n\n  getAllEntities(): OrderedMap<string, DraftEntityInstance> {\n    return DraftEntity.__getAll();\n  }\n\n  setEntityMap(\n    entityMap: OrderedMap<string, DraftEntityInstance>,\n  ): ContentState {\n    DraftEntity.__loadWithEntities(entityMap);\n    return this;\n  }\n\n  static mergeEntityMaps(\n    to: OrderedMap<string, DraftEntityInstance>,\n    from: EntityMap,\n  ): OrderedMap<string, DraftEntityInstance> {\n    return to.merge(from.__getAll());\n  }\n\n  // TODO: when EntityMap is moved into content state this and `setEntityMap`\n  // Will be the exact same. Merge them then.\n  replaceEntityMap(entityMap: EntityMap): ContentState {\n    return this.setEntityMap(entityMap.__getAll());\n  }\n\n  setSelectionBefore(selection: SelectionState): ContentState {\n    // $FlowFixMe[prop-missing] found when removing casts of this to any\n    return this.set('selectionBefore', selection);\n  }\n\n  setSelectionAfter(selection: SelectionState): ContentState {\n    // $FlowFixMe[prop-missing] found when removing casts of this to any\n    return this.set('selectionAfter', selection);\n  }\n\n  setBlockMap(blockMap: BlockMap): ContentState {\n    // $FlowFixMe[prop-missing] found when removing casts of this to any\n    return this.set('blockMap', blockMap);\n  }\n\n  static createFromBlockArray(\n    // TODO: update flow type when we completely deprecate the old entity API\n    blocks:\n      | Array<BlockNodeRecord>\n      | {contentBlocks: Array<BlockNodeRecord>, ...},\n    entityMap: ?any,\n  ): ContentState {\n    // TODO: remove this when we completely deprecate the old entity API\n    const theBlocks = Array.isArray(blocks) ? blocks : blocks.contentBlocks;\n    const blockMap = BlockMapBuilder.createFromArray(theBlocks);\n    const selectionState = blockMap.isEmpty()\n      ? new SelectionState()\n      : SelectionState.createEmpty(blockMap.first().getKey());\n    return new ContentState({\n      blockMap,\n      entityMap: entityMap || DraftEntity,\n      selectionBefore: selectionState,\n      selectionAfter: selectionState,\n    });\n  }\n\n  static createFromText(\n    text: string,\n    delimiter?: string | RegExp = /\\r\\n?|\\n/g,\n  ): ContentState {\n    const strings = text.split(delimiter);\n    const blocks = strings.map(block => {\n      block = sanitizeDraftText(block);\n      return new ContentBlockNodeRecord({\n        key: generateRandomKey(),\n        text: block,\n        type: 'unstyled',\n        characterList: List(Repeat(CharacterMetadata.EMPTY, block.length)),\n      });\n    });\n    return ContentState.createFromBlockArray(blocks);\n  }\n\n  static fromJS(state: ContentStateRawType): ContentState {\n    return new ContentState({\n      ...state,\n      blockMap: OrderedMap<string, BlockNodeRawConfig>(state.blockMap).map(\n        // $FlowFixMe[method-unbinding]\n        ContentState.createContentBlockFromJS,\n      ),\n      selectionBefore: new SelectionState(state.selectionBefore),\n      selectionAfter: new SelectionState(state.selectionAfter),\n    });\n  }\n\n  static createContentBlockFromJS(\n    block: BlockNodeRawConfig,\n  ): ContentBlockNodeRecord {\n    const characterList = block.characterList;\n\n    return new ContentBlockNodeRecord({\n      ...block,\n      data: ImmutableMap(block.data),\n      characterList:\n        characterList != null\n          ? List(\n              (Array.isArray(characterList)\n                ? characterList\n                : getOwnObjectValues(characterList)\n              ).map(c => CharacterMetadata.fromJS(c)),\n            )\n          : undefined,\n    });\n  }\n}\n\nmodule.exports = ContentState;\n"
  },
  {
    "path": "src/model/immutable/ContentStateRawType.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRawConfig} from 'BlockNode';\n\nexport type ContentStateRawType = {\n  entityMap: ?{...},\n  blockMap: ?Map<string, BlockNodeRawConfig>,\n  selectionBefore: ?{...},\n  selectionAfter: ?{...},\n  ...\n};\n"
  },
  {
    "path": "src/model/immutable/DefaultDraftBlockRenderMap.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {DraftBlockRenderConfig} from 'DraftBlockRenderConfig';\nimport type {CoreDraftBlockType} from 'DraftBlockType';\n\nconst cx = require('cx');\nconst {Map} = require('immutable');\nconst React = require('react');\n\ntype DefaultCoreDraftBlockRenderMap = Map<\n  CoreDraftBlockType,\n  DraftBlockRenderConfig,\n>;\n\nconst UL_WRAP = <ul className={cx('public/DraftStyleDefault/ul')} />;\nconst OL_WRAP = <ol className={cx('public/DraftStyleDefault/ol')} />;\nconst PRE_WRAP = <pre className={cx('public/DraftStyleDefault/pre')} />;\n\nconst DefaultDraftBlockRenderMap: DefaultCoreDraftBlockRenderMap = Map({\n  'header-one': {\n    element: 'h1',\n  },\n  'header-two': {\n    element: 'h2',\n  },\n  'header-three': {\n    element: 'h3',\n  },\n  'header-four': {\n    element: 'h4',\n  },\n  'header-five': {\n    element: 'h5',\n  },\n  'header-six': {\n    element: 'h6',\n  },\n  section: {\n    element: 'section',\n  },\n  article: {\n    element: 'article',\n  },\n  'unordered-list-item': {\n    element: 'li',\n    wrapper: UL_WRAP,\n  },\n  'ordered-list-item': {\n    element: 'li',\n    wrapper: OL_WRAP,\n  },\n  blockquote: {\n    element: 'blockquote',\n  },\n  atomic: {\n    element: 'figure',\n  },\n  'code-block': {\n    element: 'pre',\n    wrapper: PRE_WRAP,\n  },\n  unstyled: {\n    element: 'div',\n    aliasedElements: ['p'],\n  },\n});\n\nmodule.exports = DefaultDraftBlockRenderMap;\n"
  },
  {
    "path": "src/model/immutable/DefaultDraftInlineStyle.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nmodule.exports = {\n  BOLD: {\n    fontWeight: 'bold',\n  },\n\n  CODE: {\n    fontFamily: 'monospace',\n    wordWrap: 'break-word',\n  },\n\n  ITALIC: {\n    fontStyle: 'italic',\n  },\n\n  STRIKETHROUGH: {\n    textDecoration: 'line-through',\n  },\n\n  UNDERLINE: {\n    textDecoration: 'underline',\n  },\n};\n"
  },
  {
    "path": "src/model/immutable/DraftBlockRenderConfig.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport * as React from 'react';\n\nexport type DraftBlockRenderConfig = {\n  element: string,\n  wrapper?: React.Node,\n  aliasedElements?: Array<string>,\n};\n"
  },
  {
    "path": "src/model/immutable/DraftBlockRenderMap.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {DraftBlockRenderConfig} from 'DraftBlockRenderConfig';\nimport type {Map} from 'immutable';\n\n// We should be able to be more specific on the key type\n// once we upgrade to immutable v4\n// https://github.com/facebook/immutable-js/issues/1371\nexport type DraftBlockRenderMap = Map<any, DraftBlockRenderConfig>;\n"
  },
  {
    "path": "src/model/immutable/DraftInlineStyle.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type Immutable from 'immutable';\n\nexport type DraftInlineStyle = Immutable.OrderedSet<string>;\n"
  },
  {
    "path": "src/model/immutable/EditorBidiService.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type ContentState from 'ContentState';\n\nconst UnicodeBidiService = require('UnicodeBidiService');\n\nconst Immutable = require('immutable');\nconst nullthrows = require('nullthrows');\n\nconst {OrderedMap} = Immutable;\n\nlet bidiService;\n\nconst EditorBidiService = {\n  getDirectionMap(\n    content: ContentState,\n    prevBidiMap: ?OrderedMap<any, any>,\n  ): OrderedMap<any, any> {\n    if (!bidiService) {\n      bidiService = new UnicodeBidiService();\n    } else {\n      bidiService.reset();\n    }\n\n    const blockMap = content.getBlockMap();\n    const nextBidi = blockMap\n      .valueSeq()\n      .map(block => nullthrows(bidiService).getDirection(block.getText()));\n    const bidiMap = OrderedMap(blockMap.keySeq().zip(nextBidi));\n\n    if (prevBidiMap != null && Immutable.is(prevBidiMap, bidiMap)) {\n      return prevBidiMap;\n    }\n\n    return bidiMap;\n  },\n};\n\nmodule.exports = EditorBidiService;\n"
  },
  {
    "path": "src/model/immutable/EditorChangeType.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nexport type EditorChangeType =\n  | 'adjust-depth'\n  | 'apply-entity'\n  | 'backspace-character'\n  | 'change-block-data'\n  | 'change-block-type'\n  | 'change-inline-style'\n  | 'move-block'\n  | 'delete-character'\n  | 'insert-characters'\n  | 'insert-fragment'\n  | 'redo'\n  | 'remove-range'\n  | 'spellcheck-change'\n  | 'split-block'\n  | 'undo';\n"
  },
  {
    "path": "src/model/immutable/EditorState.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockMap} from 'BlockMap';\nimport type {DecoratorRangeRawType} from 'BlockTree';\nimport type {ContentStateRawType} from 'ContentStateRawType';\nimport type {DraftDecoratorType} from 'DraftDecoratorType';\nimport type {DraftInlineStyle} from 'DraftInlineStyle';\nimport type {EditorChangeType} from 'EditorChangeType';\nimport type {EntityMap} from 'EntityMap';\n\nconst BlockTree = require('BlockTree');\nconst ContentState = require('ContentState');\nconst EditorBidiService = require('EditorBidiService');\nconst SelectionState = require('SelectionState');\n\nconst Immutable = require('immutable');\n\nconst {OrderedSet, Record, Stack, OrderedMap, List} = Immutable;\n\n// When configuring an editor, the user can chose to provide or not provide\n// basically all keys. `currentContent` varies, so this type doesn't include it.\n// (See the types defined below.)\ntype BaseEditorStateConfig = {\n  allowUndo?: boolean,\n  decorator?: ?DraftDecoratorType,\n  directionMap?: ?OrderedMap<string, string>,\n  forceSelection?: boolean,\n  inCompositionMode?: boolean,\n  inlineStyleOverride?: ?DraftInlineStyle,\n  lastChangeType?: ?EditorChangeType,\n  nativelyRenderedContent?: ?ContentState,\n  redoStack?: Stack<ContentState>,\n  selection?: ?SelectionState,\n  treeMap?: ?OrderedMap<string, List<any>>,\n  undoStack?: Stack<ContentState>,\n};\n\ntype BaseEditorStateRawConfig = {\n  allowUndo?: boolean,\n  decorator?: ?DraftDecoratorType,\n  directionMap?: ?{...},\n  forceSelection?: boolean,\n  inCompositionMode?: boolean,\n  inlineStyleOverride?: ?Array<String>,\n  lastChangeType?: ?EditorChangeType,\n  nativelyRenderedContent?: ?ContentStateRawType,\n  redoStack?: Array<ContentStateRawType>,\n  selection?: ?{...},\n  treeMap?: ?Map<string, Array<DecoratorRangeRawType>>,\n  undoStack?: Array<ContentStateRawType>,\n};\n\n// When crating an editor, we want currentContent to be set.\ntype EditorStateCreationConfigType = {\n  ...BaseEditorStateConfig,\n  currentContent: ContentState,\n};\n\ntype EditorStateCreationConfigRawType = {\n  ...BaseEditorStateRawConfig,\n  currentContent: ContentStateRawType,\n};\n\n// When using EditorState.set(...), currentContent is optional\ntype EditorStateChangeConfigType = {\n  ...BaseEditorStateConfig,\n  currentContent?: ?ContentState,\n};\n\ntype EditorStateRecordType = {\n  allowUndo: boolean,\n  currentContent: ?ContentState,\n  decorator: ?DraftDecoratorType,\n  directionMap: ?OrderedMap<string, string>,\n  forceSelection: boolean,\n  inCompositionMode: boolean,\n  inlineStyleOverride: ?DraftInlineStyle,\n  lastChangeType: ?EditorChangeType,\n  nativelyRenderedContent: ?ContentState,\n  redoStack: Stack<ContentState>,\n  selection: ?SelectionState,\n  treeMap: ?OrderedMap<string, List<any>>,\n  undoStack: Stack<ContentState>,\n  ...\n};\n\nconst defaultRecord: EditorStateRecordType = {\n  allowUndo: true,\n  currentContent: null,\n  decorator: null,\n  directionMap: null,\n  forceSelection: false,\n  inCompositionMode: false,\n  inlineStyleOverride: null,\n  lastChangeType: null,\n  nativelyRenderedContent: null,\n  redoStack: Stack(),\n  selection: null,\n  treeMap: null,\n  undoStack: Stack(),\n};\n\nconst EditorStateRecord = (Record(defaultRecord): any);\n\nclass EditorState {\n  // $FlowFixMe[value-as-type]\n  _immutable: EditorStateRecord;\n\n  static createEmpty(decorator?: ?DraftDecoratorType): EditorState {\n    return this.createWithText('', decorator);\n  }\n\n  static createWithText(\n    text: string,\n    decorator?: ?DraftDecoratorType,\n  ): EditorState {\n    return EditorState.createWithContent(\n      ContentState.createFromText(text),\n      decorator,\n    );\n  }\n\n  static createWithContent(\n    contentState: ContentState,\n    decorator?: ?DraftDecoratorType,\n  ): EditorState {\n    if (contentState.getBlockMap().count() === 0) {\n      return EditorState.createEmpty(decorator);\n    }\n    const firstKey = contentState.getBlockMap().first().getKey();\n    return EditorState.create({\n      currentContent: contentState,\n      undoStack: Stack(),\n      redoStack: Stack(),\n      decorator: decorator || null,\n      selection: SelectionState.createEmpty(firstKey),\n    });\n  }\n\n  static create(config: EditorStateCreationConfigType): EditorState {\n    const {currentContent, decorator} = config;\n    const recordConfig = {\n      ...config,\n      treeMap: generateNewTreeMap(currentContent, decorator),\n      directionMap: EditorBidiService.getDirectionMap(currentContent),\n    };\n    return new EditorState(new EditorStateRecord(recordConfig));\n  }\n\n  static fromJS(config: EditorStateCreationConfigRawType): EditorState {\n    return new EditorState(\n      new EditorStateRecord({\n        ...config,\n        directionMap:\n          config.directionMap != null\n            ? OrderedMap(config.directionMap)\n            : config.directionMap,\n        inlineStyleOverride:\n          config.inlineStyleOverride != null\n            ? OrderedSet(config.inlineStyleOverride)\n            : config.inlineStyleOverride,\n        nativelyRenderedContent:\n          config.nativelyRenderedContent != null\n            ? ContentState.fromJS(config.nativelyRenderedContent)\n            : config.nativelyRenderedContent,\n        redoStack:\n          config.redoStack != null\n            ? Stack(config.redoStack.map(v => ContentState.fromJS(v)))\n            : config.redoStack,\n        selection:\n          config.selection != null\n            ? new SelectionState(config.selection)\n            : config.selection,\n        treeMap:\n          config.treeMap != null\n            ? OrderedMap(config.treeMap).map(v =>\n                List(v).map(v => BlockTree.fromJS(v)),\n              )\n            : config.treeMap,\n        undoStack:\n          config.undoStack != null\n            ? Stack(config.undoStack.map(v => ContentState.fromJS(v)))\n            : config.undoStack,\n        currentContent: ContentState.fromJS(config.currentContent),\n      }),\n    );\n  }\n\n  static set(\n    editorState: EditorState,\n    put: EditorStateChangeConfigType,\n  ): EditorState {\n    const map = editorState.getImmutable().withMutations(state => {\n      const existingDecorator = state.get('decorator');\n      let decorator: ?DraftDecoratorType = existingDecorator;\n      if (put.decorator === null) {\n        decorator = null;\n      } else if (put.decorator) {\n        decorator = put.decorator;\n      }\n\n      const newContent = put.currentContent || editorState.getCurrentContent();\n\n      if (decorator !== existingDecorator) {\n        const treeMap: OrderedMap<string, any> = state.get('treeMap');\n        let newTreeMap;\n        if (decorator && existingDecorator) {\n          newTreeMap = regenerateTreeForNewDecorator(\n            newContent,\n            newContent.getBlockMap(),\n            treeMap,\n            decorator,\n            existingDecorator,\n          );\n        } else {\n          newTreeMap = generateNewTreeMap(newContent, decorator);\n        }\n\n        state.merge({\n          decorator,\n          treeMap: newTreeMap,\n          nativelyRenderedContent: null,\n        });\n        return;\n      }\n\n      const existingContent = editorState.getCurrentContent();\n      if (newContent !== existingContent) {\n        state.set(\n          'treeMap',\n          regenerateTreeForNewBlocks(\n            editorState,\n            newContent.getBlockMap(),\n            newContent.getEntityMap(),\n            decorator,\n          ),\n        );\n      }\n\n      state.merge(put);\n    });\n\n    return new EditorState(map);\n  }\n\n  toJS(): Object {\n    return this.getImmutable().toJS();\n  }\n\n  getAllowUndo(): boolean {\n    return this.getImmutable().get('allowUndo');\n  }\n\n  getCurrentContent(): ContentState {\n    return this.getImmutable().get('currentContent');\n  }\n\n  getUndoStack(): Stack<ContentState> {\n    return this.getImmutable().get('undoStack');\n  }\n\n  getRedoStack(): Stack<ContentState> {\n    return this.getImmutable().get('redoStack');\n  }\n\n  getSelection(): SelectionState {\n    return this.getImmutable().get('selection');\n  }\n\n  getDecorator(): ?DraftDecoratorType {\n    return this.getImmutable().get('decorator');\n  }\n\n  isInCompositionMode(): boolean {\n    return this.getImmutable().get('inCompositionMode');\n  }\n\n  mustForceSelection(): boolean {\n    return this.getImmutable().get('forceSelection');\n  }\n\n  getNativelyRenderedContent(): ?ContentState {\n    return this.getImmutable().get('nativelyRenderedContent');\n  }\n\n  getLastChangeType(): ?EditorChangeType {\n    return this.getImmutable().get('lastChangeType');\n  }\n\n  /**\n   * While editing, the user may apply inline style commands with a collapsed\n   * cursor, intending to type text that adopts the specified style. In this\n   * case, we track the specified style as an \"override\" that takes precedence\n   * over the inline style of the text adjacent to the cursor.\n   *\n   * If null, there is no override in place.\n   */\n  getInlineStyleOverride(): ?DraftInlineStyle {\n    return this.getImmutable().get('inlineStyleOverride');\n  }\n\n  static setInlineStyleOverride(\n    editorState: EditorState,\n    inlineStyleOverride: DraftInlineStyle,\n  ): EditorState {\n    return EditorState.set(editorState, {inlineStyleOverride});\n  }\n\n  /**\n   * Get the appropriate inline style for the editor state. If an\n   * override is in place, use it. Otherwise, the current style is\n   * based on the location of the selection state.\n   */\n  getCurrentInlineStyle(): DraftInlineStyle {\n    const override = this.getInlineStyleOverride();\n    if (override != null) {\n      return override;\n    }\n\n    const content = this.getCurrentContent();\n    const selection = this.getSelection();\n\n    if (selection.isCollapsed()) {\n      return getInlineStyleForCollapsedSelection(content, selection);\n    }\n\n    return getInlineStyleForNonCollapsedSelection(content, selection);\n  }\n\n  getBlockTree(blockKey: string): List<any> {\n    return this.getImmutable().getIn(['treeMap', blockKey]);\n  }\n\n  isSelectionAtStartOfContent(): boolean {\n    const firstKey = this.getCurrentContent().getBlockMap().first().getKey();\n    return this.getSelection().hasEdgeWithin(firstKey, 0, 0);\n  }\n\n  isSelectionAtEndOfContent(): boolean {\n    const content = this.getCurrentContent();\n    const blockMap = content.getBlockMap();\n    const last = blockMap.last();\n    const end = last.getLength();\n    return this.getSelection().hasEdgeWithin(last.getKey(), end, end);\n  }\n\n  getDirectionMap(): ?OrderedMap<any, any> {\n    return this.getImmutable().get('directionMap');\n  }\n\n  /**\n   * Incorporate native DOM selection changes into the EditorState. This\n   * method can be used when we simply want to accept whatever the DOM\n   * has given us to represent selection, and we do not need to re-render\n   * the editor.\n   *\n   * To forcibly move the DOM selection, see `EditorState.forceSelection`.\n   */\n  static acceptSelection(\n    editorState: EditorState,\n    selection: SelectionState,\n  ): EditorState {\n    return updateSelection(editorState, selection, false);\n  }\n\n  /**\n   * At times, we need to force the DOM selection to be where we\n   * need it to be. This can occur when the anchor or focus nodes\n   * are non-text nodes, for instance. In this case, we want to trigger\n   * a re-render of the editor, which in turn forces selection into\n   * the correct place in the DOM. The `forceSelection` method\n   * accomplishes this.\n   *\n   * This method should be used in cases where you need to explicitly\n   * move the DOM selection from one place to another without a change\n   * in ContentState.\n   */\n  static forceSelection(\n    editorState: EditorState,\n    selection: SelectionState,\n  ): EditorState {\n    if (!selection.getHasFocus()) {\n      selection = selection.set('hasFocus', true);\n    }\n    return updateSelection(editorState, selection, true);\n  }\n\n  /**\n   * Move selection to the end of the editor without forcing focus.\n   */\n  static moveSelectionToEnd(editorState: EditorState): EditorState {\n    const content = editorState.getCurrentContent();\n    const lastBlock = content.getLastBlock();\n    const lastKey = lastBlock.getKey();\n    const length = lastBlock.getLength();\n\n    return EditorState.acceptSelection(\n      editorState,\n      new SelectionState({\n        anchorKey: lastKey,\n        anchorOffset: length,\n        focusKey: lastKey,\n        focusOffset: length,\n        isBackward: false,\n      }),\n    );\n  }\n\n  /**\n   * Force focus to the end of the editor. This is useful in scenarios\n   * where we want to programmatically focus the input and it makes sense\n   * to allow the user to continue working seamlessly.\n   */\n  static moveFocusToEnd(editorState: EditorState): EditorState {\n    const afterSelectionMove = EditorState.moveSelectionToEnd(editorState);\n    return EditorState.forceSelection(\n      afterSelectionMove,\n      afterSelectionMove.getSelection(),\n    );\n  }\n\n  /**\n   * Push the current ContentState onto the undo stack if it should be\n   * considered a boundary state, and set the provided ContentState as the\n   * new current content.\n   */\n  static push(\n    editorState: EditorState,\n    contentState: ContentState,\n    changeType: EditorChangeType,\n    forceSelection: boolean = true,\n  ): EditorState {\n    if (editorState.getCurrentContent() === contentState) {\n      return editorState;\n    }\n\n    const directionMap = EditorBidiService.getDirectionMap(\n      contentState,\n      editorState.getDirectionMap(),\n    );\n\n    if (!editorState.getAllowUndo()) {\n      return EditorState.set(editorState, {\n        currentContent: contentState,\n        directionMap,\n        lastChangeType: changeType,\n        selection: contentState.getSelectionAfter(),\n        forceSelection,\n        inlineStyleOverride: null,\n      });\n    }\n\n    const selection = editorState.getSelection();\n    const currentContent = editorState.getCurrentContent();\n    let undoStack = editorState.getUndoStack();\n    let newContent = contentState;\n\n    if (\n      selection !== currentContent.getSelectionAfter() ||\n      mustBecomeBoundary(editorState, changeType)\n    ) {\n      undoStack = undoStack.push(currentContent);\n      newContent = newContent.setSelectionBefore(selection);\n    } else if (\n      changeType === 'insert-characters' ||\n      changeType === 'backspace-character' ||\n      changeType === 'delete-character'\n    ) {\n      // Preserve the previous selection.\n      newContent = newContent.setSelectionBefore(\n        currentContent.getSelectionBefore(),\n      );\n    }\n\n    let inlineStyleOverride = editorState.getInlineStyleOverride();\n\n    // Don't discard inline style overrides for the following change types:\n    const overrideChangeTypes = [\n      'adjust-depth',\n      'change-block-type',\n      'split-block',\n    ];\n\n    if (overrideChangeTypes.indexOf(changeType) === -1) {\n      inlineStyleOverride = null;\n    }\n\n    const editorStateChanges = {\n      currentContent: newContent,\n      directionMap,\n      undoStack,\n      redoStack: Stack<ContentState>(),\n      lastChangeType: changeType,\n      selection: contentState.getSelectionAfter(),\n      forceSelection,\n      inlineStyleOverride,\n    };\n\n    return EditorState.set(editorState, editorStateChanges);\n  }\n\n  /**\n   * Make the top ContentState in the undo stack the new current content and\n   * push the current content onto the redo stack.\n   */\n  static undo(editorState: EditorState): EditorState {\n    if (!editorState.getAllowUndo()) {\n      return editorState;\n    }\n\n    const undoStack = editorState.getUndoStack();\n    const newCurrentContent = undoStack.peek();\n    if (!newCurrentContent) {\n      return editorState;\n    }\n\n    const currentContent = editorState.getCurrentContent();\n    const directionMap = EditorBidiService.getDirectionMap(\n      newCurrentContent,\n      editorState.getDirectionMap(),\n    );\n\n    return EditorState.set(editorState, {\n      currentContent: newCurrentContent,\n      directionMap,\n      undoStack: undoStack.shift(),\n      redoStack: editorState.getRedoStack().push(currentContent),\n      forceSelection: true,\n      inlineStyleOverride: null,\n      lastChangeType: 'undo',\n      nativelyRenderedContent: null,\n      selection: currentContent.getSelectionBefore(),\n    });\n  }\n\n  /**\n   * Make the top ContentState in the redo stack the new current content and\n   * push the current content onto the undo stack.\n   */\n  static redo(editorState: EditorState): EditorState {\n    if (!editorState.getAllowUndo()) {\n      return editorState;\n    }\n\n    const redoStack = editorState.getRedoStack();\n    const newCurrentContent = redoStack.peek();\n    if (!newCurrentContent) {\n      return editorState;\n    }\n\n    const currentContent = editorState.getCurrentContent();\n    const directionMap = EditorBidiService.getDirectionMap(\n      newCurrentContent,\n      editorState.getDirectionMap(),\n    );\n\n    return EditorState.set(editorState, {\n      currentContent: newCurrentContent,\n      directionMap,\n      undoStack: editorState.getUndoStack().push(currentContent),\n      redoStack: redoStack.shift(),\n      forceSelection: true,\n      inlineStyleOverride: null,\n      lastChangeType: 'redo',\n      nativelyRenderedContent: null,\n      selection: newCurrentContent.getSelectionAfter(),\n    });\n  }\n\n  /**\n   * Not for public consumption.\n   */\n  // $FlowFixMe[value-as-type]\n  constructor(immutable: EditorStateRecord) {\n    this._immutable = immutable;\n  }\n\n  /**\n   * Not for public consumption.\n   */\n  // $FlowFixMe[value-as-type]\n  getImmutable(): EditorStateRecord {\n    return this._immutable;\n  }\n}\n\n/**\n * Set the supplied SelectionState as the new current selection, and set\n * the `force` flag to trigger manual selection placement by the view.\n */\nfunction updateSelection(\n  editorState: EditorState,\n  selection: SelectionState,\n  forceSelection: boolean,\n): EditorState {\n  return EditorState.set(editorState, {\n    selection,\n    forceSelection,\n    nativelyRenderedContent: null,\n    inlineStyleOverride: null,\n  });\n}\n\n/**\n * Regenerate the entire tree map for a given ContentState and decorator.\n * Returns an OrderedMap that maps all available ContentBlock objects.\n */\nfunction generateNewTreeMap(\n  contentState: ContentState,\n  decorator?: ?DraftDecoratorType,\n): OrderedMap<string, List<any>> {\n  return contentState\n    .getBlockMap()\n    .map(block => BlockTree.generate(contentState, block, decorator))\n    .toOrderedMap();\n}\n\n/**\n * Regenerate tree map objects for all ContentBlocks that have changed\n * between the current editorState and newContent. Returns an OrderedMap\n * with only changed regenerated tree map objects.\n */\nfunction regenerateTreeForNewBlocks(\n  editorState: EditorState,\n  newBlockMap: BlockMap,\n  newEntityMap: EntityMap,\n  decorator?: ?DraftDecoratorType,\n): OrderedMap<string, List<any>> {\n  const contentState = editorState\n    .getCurrentContent()\n    .replaceEntityMap(newEntityMap);\n  const prevBlockMap = contentState.getBlockMap();\n  const prevTreeMap = editorState.getImmutable().get('treeMap');\n  return prevTreeMap.merge(\n    newBlockMap\n      .toSeq()\n      .filter((block, key) => block !== prevBlockMap.get(key))\n      .map(block => BlockTree.generate(contentState, block, decorator)),\n  );\n}\n\n/**\n * Generate tree map objects for a new decorator object, preserving any\n * decorations that are unchanged from the previous decorator.\n *\n * Note that in order for this to perform optimally, decoration Lists for\n * decorators should be preserved when possible to allow for direct immutable\n * List comparison.\n */\nfunction regenerateTreeForNewDecorator(\n  content: ContentState,\n  blockMap: BlockMap,\n  previousTreeMap: OrderedMap<string, List<any>>,\n  decorator: DraftDecoratorType,\n  existingDecorator: DraftDecoratorType,\n): OrderedMap<string, List<any>> {\n  return previousTreeMap.merge(\n    blockMap\n      .toSeq()\n      .filter(block => {\n        return (\n          decorator.getDecorations(block, content) !==\n          existingDecorator.getDecorations(block, content)\n        );\n      })\n      .map(block => BlockTree.generate(content, block, decorator)),\n  );\n}\n\n/**\n * Return whether a change should be considered a boundary state, given\n * the previous change type. Allows us to discard potential boundary states\n * during standard typing or deletion behavior.\n */\nfunction mustBecomeBoundary(\n  editorState: EditorState,\n  changeType: EditorChangeType,\n): boolean {\n  const lastChangeType = editorState.getLastChangeType();\n  return (\n    changeType !== lastChangeType ||\n    (changeType !== 'insert-characters' &&\n      changeType !== 'backspace-character' &&\n      changeType !== 'delete-character')\n  );\n}\n\nfunction getInlineStyleForCollapsedSelection(\n  content: ContentState,\n  selection: SelectionState,\n): DraftInlineStyle {\n  const startKey = selection.getStartKey();\n  const startOffset = selection.getStartOffset();\n  const startBlock = content.getBlockForKey(startKey);\n\n  // If the cursor is not at the start of the block, look backward to\n  // preserve the style of the preceding character.\n  if (startOffset > 0) {\n    return startBlock.getInlineStyleAt(startOffset - 1);\n  }\n\n  // The caret is at position zero in this block. If the block has any\n  // text at all, use the style of the first character.\n  if (startBlock.getLength()) {\n    return startBlock.getInlineStyleAt(0);\n  }\n\n  // Otherwise, look upward in the document to find the closest character.\n  return lookUpwardForInlineStyle(content, startKey);\n}\n\nfunction getInlineStyleForNonCollapsedSelection(\n  content: ContentState,\n  selection: SelectionState,\n): DraftInlineStyle {\n  const startKey = selection.getStartKey();\n  const startOffset = selection.getStartOffset();\n  const startBlock = content.getBlockForKey(startKey);\n\n  // If there is a character just inside the selection, use its style.\n  if (startOffset < startBlock.getLength()) {\n    return startBlock.getInlineStyleAt(startOffset);\n  }\n\n  // Check if the selection at the end of a non-empty block. Use the last\n  // style in the block.\n  if (startOffset > 0) {\n    return startBlock.getInlineStyleAt(startOffset - 1);\n  }\n\n  // Otherwise, look upward in the document to find the closest character.\n  return lookUpwardForInlineStyle(content, startKey);\n}\n\nfunction lookUpwardForInlineStyle(\n  content: ContentState,\n  fromKey: string,\n): DraftInlineStyle {\n  const lastNonEmpty = content\n    .getBlockMap()\n    .reverse()\n    .skipUntil((_, k) => k === fromKey)\n    .skip(1)\n    .skipUntil((block, _) => block.getLength())\n    .first();\n\n  if (lastNonEmpty) {\n    return lastNonEmpty.getInlineStyleAt(lastNonEmpty.getLength() - 1);\n  }\n  return OrderedSet();\n}\n\nmodule.exports = EditorState;\n"
  },
  {
    "path": "src/model/immutable/EntityMap.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {DraftEntityMapObject} from 'DraftEntity';\n\n// TODO: when removing the deprecated Entity api\n// change this to be\n// OrderedMap<string, DraftEntityInstance>;\nexport type EntityMap = DraftEntityMapObject;\n"
  },
  {
    "path": "src/model/immutable/SampleDraftInlineStyle.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst {OrderedSet} = require('immutable');\n\nmodule.exports = {\n  BOLD: (OrderedSet.of('BOLD'): OrderedSet<string>),\n  BOLD_ITALIC: (OrderedSet.of('BOLD', 'ITALIC'): OrderedSet<string>),\n  BOLD_ITALIC_UNDERLINE: (OrderedSet.of(\n    'BOLD',\n    'ITALIC',\n    'UNDERLINE',\n  ): OrderedSet<string>),\n  BOLD_UNDERLINE: (OrderedSet.of('BOLD', 'UNDERLINE'): OrderedSet<string>),\n  CODE: (OrderedSet.of('CODE'): OrderedSet<string>),\n  ITALIC: (OrderedSet.of('ITALIC'): OrderedSet<string>),\n  ITALIC_UNDERLINE: (OrderedSet.of('ITALIC', 'UNDERLINE'): OrderedSet<string>),\n  NONE: (OrderedSet(): OrderedSet<string>),\n  STRIKETHROUGH: (OrderedSet.of('STRIKETHROUGH'): OrderedSet<string>),\n  UNDERLINE: (OrderedSet.of('UNDERLINE'): OrderedSet<string>),\n};\n"
  },
  {
    "path": "src/model/immutable/SelectionState.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst Immutable = require('immutable');\n\nconst {Record} = Immutable;\n\nconst defaultRecord: {\n  anchorKey: string,\n  anchorOffset: number,\n  focusKey: string,\n  focusOffset: number,\n  isBackward: boolean,\n  hasFocus: boolean,\n  ...\n} = {\n  anchorKey: '',\n  anchorOffset: 0,\n  focusKey: '',\n  focusOffset: 0,\n  isBackward: false,\n  hasFocus: false,\n};\n\n/* $FlowFixMe[unclear-type] This comment suppresses an error found when\n * automatically adding a type annotation with the codemod Komodo/Annotate_\n * exports. To see the error delete this comment and run Flow. */\nconst SelectionStateRecord = (Record(defaultRecord): any);\n\nclass SelectionState extends SelectionStateRecord {\n  serialize(): string {\n    return (\n      'Anchor: ' +\n      this.getAnchorKey() +\n      ':' +\n      this.getAnchorOffset() +\n      ', ' +\n      'Focus: ' +\n      this.getFocusKey() +\n      ':' +\n      this.getFocusOffset() +\n      ', ' +\n      'Is Backward: ' +\n      String(this.getIsBackward()) +\n      ', ' +\n      'Has Focus: ' +\n      String(this.getHasFocus())\n    );\n  }\n\n  getAnchorKey(): string {\n    return this.get('anchorKey');\n  }\n\n  getAnchorOffset(): number {\n    return this.get('anchorOffset');\n  }\n\n  getFocusKey(): string {\n    return this.get('focusKey');\n  }\n\n  getFocusOffset(): number {\n    return this.get('focusOffset');\n  }\n\n  getIsBackward(): boolean {\n    return this.get('isBackward');\n  }\n\n  getHasFocus(): boolean {\n    return this.get('hasFocus');\n  }\n\n  /**\n   * Return whether the specified range overlaps with an edge of the\n   * SelectionState.\n   */\n  hasEdgeWithin(blockKey: string, start: number, end: number): boolean {\n    const anchorKey = this.getAnchorKey();\n    const focusKey = this.getFocusKey();\n\n    if (anchorKey === focusKey && anchorKey === blockKey) {\n      const selectionStart = this.getStartOffset();\n      const selectionEnd = this.getEndOffset();\n      return (\n        (start <= selectionStart && selectionStart <= end) || // selectionStart is between start and end, or\n        (start <= selectionEnd && selectionEnd <= end) // selectionEnd is between start and end\n      );\n    }\n\n    if (blockKey !== anchorKey && blockKey !== focusKey) {\n      return false;\n    }\n\n    const offsetToCheck =\n      blockKey === anchorKey ? this.getAnchorOffset() : this.getFocusOffset();\n\n    return start <= offsetToCheck && end >= offsetToCheck;\n  }\n\n  isCollapsed(): boolean {\n    return (\n      this.getAnchorKey() === this.getFocusKey() &&\n      this.getAnchorOffset() === this.getFocusOffset()\n    );\n  }\n\n  getStartKey(): string {\n    return this.getIsBackward() ? this.getFocusKey() : this.getAnchorKey();\n  }\n\n  getStartOffset(): number {\n    return this.getIsBackward()\n      ? this.getFocusOffset()\n      : this.getAnchorOffset();\n  }\n\n  getEndKey(): string {\n    return this.getIsBackward() ? this.getAnchorKey() : this.getFocusKey();\n  }\n\n  getEndOffset(): number {\n    return this.getIsBackward()\n      ? this.getAnchorOffset()\n      : this.getFocusOffset();\n  }\n\n  static createEmpty(key: string): SelectionState {\n    return new SelectionState({\n      anchorKey: key,\n      anchorOffset: 0,\n      focusKey: key,\n      focusOffset: 0,\n      isBackward: false,\n      hasFocus: false,\n    });\n  }\n}\n\nmodule.exports = SelectionState;\n"
  },
  {
    "path": "src/model/immutable/__tests__/BlockTree-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst BlockTree = require('BlockTree');\nconst CharacterMetadata = require('CharacterMetadata');\nconst ContentBlock = require('ContentBlock');\nconst ContentState = require('ContentState');\nconst {BOLD} = require('SampleDraftInlineStyle');\n\nconst Immutable = require('immutable');\n\nconst {EMPTY} = CharacterMetadata;\n\nconst {Repeat} = Immutable;\n\nconst PLAIN_BLOCK = {\n  key: 'a',\n  text: 'Lincoln',\n  characterList: Repeat(EMPTY, 7).toList(),\n};\n\nconst STYLED_BLOCK = {\n  key: 'b',\n  text: 'Washington',\n  characterList: Repeat(EMPTY, 4).concat(\n    Repeat(CharacterMetadata.create({style: BOLD}), 4),\n    Repeat(EMPTY, 2),\n  ),\n};\n\nclass Decorator {}\nDecorator.prototype.getDecorations = jest.fn();\n\nbeforeEach(() => {\n  jest.resetModules();\n});\n\n// empty decorator\nconst emptyDecoratorFactory = length => {\n  Decorator.prototype.getDecorations.mockImplementation(() =>\n    Repeat(null, length).toList(),\n  );\n  return new Decorator();\n};\n\n// single decorator\nconst singleDecoratorFactory = length => {\n  const DECORATOR_KEY = 'x';\n  const RANGE_LENGTH = 3;\n\n  Decorator.prototype.getDecorations.mockImplementation(() => {\n    return Repeat(null, RANGE_LENGTH)\n      .concat(\n        Repeat(DECORATOR_KEY, RANGE_LENGTH),\n        Repeat(null, length - 2 * RANGE_LENGTH),\n      )\n      .toList();\n  });\n  return new Decorator();\n};\n\nconst multiDecoratorFactory = length => {\n  const DECORATOR_KEY_A = 'y';\n  const DECORATOR_KEY_B = 'z';\n  const RANGE_LENGTH = 3;\n\n  Decorator.prototype.getDecorations.mockImplementation(() => {\n    return Repeat(DECORATOR_KEY_A, RANGE_LENGTH)\n      .concat(\n        Repeat(null, RANGE_LENGTH),\n        Repeat(DECORATOR_KEY_B, length - 2 * RANGE_LENGTH),\n      )\n      .toList();\n  });\n  return new Decorator();\n};\n\nconst assertBlockTreeGenerate = (\n  config,\n  getDecorator = emptyDecoratorFactory,\n) => {\n  const block = new ContentBlock(config);\n  const content = ContentState.createFromText(config.text);\n  const decorator = getDecorator(config.text.length);\n  const tree = BlockTree.generate(content, block, decorator);\n\n  expect(tree.toJS()).toMatchSnapshot();\n\n  // to remove\n  return tree;\n};\n\nit('must generate for unstyled block with empty decorator', () => {\n  assertBlockTreeGenerate(PLAIN_BLOCK);\n});\n\nit('must generate for styled block with empty decorator', () => {\n  assertBlockTreeGenerate(STYLED_BLOCK);\n});\n\nit('must generate for unstyled block with single decorator', () => {\n  assertBlockTreeGenerate(PLAIN_BLOCK, singleDecoratorFactory);\n});\n\nit('must generate for styled block with single decorator', () => {\n  assertBlockTreeGenerate(STYLED_BLOCK, singleDecoratorFactory);\n});\n\nit('must generate for unstyled block with multiple decorators', () => {\n  assertBlockTreeGenerate(PLAIN_BLOCK, multiDecoratorFactory);\n});\n\nit('must generate for styled block with multiple decorators', () => {\n  assertBlockTreeGenerate(STYLED_BLOCK, multiDecoratorFactory);\n});\n"
  },
  {
    "path": "src/model/immutable/__tests__/CharacterMetadata-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst CharacterMetadata = require('CharacterMetadata');\nconst {BOLD, BOLD_ITALIC, NONE, UNDERLINE} = require('SampleDraftInlineStyle');\n\nconst plain = CharacterMetadata.create();\nconst bold = CharacterMetadata.create({style: BOLD});\nconst fancy = CharacterMetadata.create({style: BOLD_ITALIC});\n\nconst withoutEntity = CharacterMetadata.create();\nconst withEntity = CharacterMetadata.create({entity: 'a'});\n\nconst withStyleAndEntity = CharacterMetadata.create({\n  entity: 'a',\n  style: BOLD,\n});\n\ntest('must have appropriate default values', () => {\n  const character = CharacterMetadata.create();\n  expect(character.toJS()).toMatchSnapshot();\n  expect(character.getStyle().size).toMatchSnapshot();\n  expect(character.getEntity()).toMatchSnapshot();\n});\n\ntest('must run `hasStyle` correctly', () => {\n  expect(plain.hasStyle('BOLD')).toMatchSnapshot();\n  expect(bold.hasStyle('BOLD')).toMatchSnapshot();\n  expect(fancy.hasStyle('BOLD')).toMatchSnapshot();\n  expect(plain.hasStyle('ITALIC')).toMatchSnapshot();\n  expect(bold.hasStyle('ITALIC')).toMatchSnapshot();\n  expect(fancy.hasStyle('ITALIC')).toMatchSnapshot();\n});\n\ntest('must apply style', () => {\n  const newlyBold = CharacterMetadata.applyStyle(plain, 'BOLD');\n  expect(newlyBold.hasStyle('BOLD')).toMatchSnapshot();\n  const alsoItalic = CharacterMetadata.applyStyle(newlyBold, 'ITALIC');\n  expect(alsoItalic.hasStyle('BOLD')).toMatchSnapshot();\n  expect(alsoItalic.hasStyle('ITALIC')).toMatchSnapshot();\n});\n\ntest('must remove style', () => {\n  const justBold = CharacterMetadata.removeStyle(fancy, 'ITALIC');\n  expect(justBold.hasStyle('BOLD')).toMatchSnapshot();\n  expect(justBold.hasStyle('ITALIC')).toMatchSnapshot();\n  const justPlain = CharacterMetadata.removeStyle(justBold, 'BOLD');\n  expect(justPlain.hasStyle('BOLD')).toMatchSnapshot();\n  expect(justPlain.hasStyle('ITALIC')).toMatchSnapshot();\n});\n\ntest('must apply entity correctly', () => {\n  const newKey = 'x';\n  const modifiedA = CharacterMetadata.applyEntity(withoutEntity, newKey);\n  const modifiedB = CharacterMetadata.applyEntity(withEntity, newKey);\n  expect(modifiedA.getEntity()).toMatchSnapshot();\n  expect(modifiedB.getEntity()).toMatchSnapshot();\n});\n\ntest('must remove entity correctly', () => {\n  const modifiedA = CharacterMetadata.applyEntity(withoutEntity, null);\n  const modifiedB = CharacterMetadata.applyEntity(withEntity, null);\n  expect(modifiedA.getEntity()).toMatchSnapshot();\n  expect(modifiedB.getEntity()).toMatchSnapshot();\n});\n\ntest('must reuse the same objects', () => {\n  expect(CharacterMetadata.create() === plain).toMatchSnapshot();\n  expect(CharacterMetadata.create({style: BOLD}) === bold).toMatchSnapshot();\n  expect(\n    CharacterMetadata.create({style: BOLD_ITALIC}) === fancy,\n  ).toMatchSnapshot();\n  expect(\n    CharacterMetadata.create({entity: 'a'}) === withEntity,\n  ).toMatchSnapshot();\n  expect(\n    CharacterMetadata.create({entity: 'a', style: BOLD}) === withStyleAndEntity,\n  ).toMatchSnapshot();\n});\n\ntest('must reuse objects by defaulting config properties', () => {\n  expect(\n    CharacterMetadata.create({style: NONE, entity: 'a'}) === withEntity,\n  ).toMatchSnapshot();\n\n  expect(\n    CharacterMetadata.create({style: BOLD, entity: null}) === bold,\n  ).toMatchSnapshot();\n\n  const underlined = CharacterMetadata.create({\n    style: UNDERLINE,\n    entity: null,\n  });\n\n  expect(\n    CharacterMetadata.create({style: UNDERLINE}) === underlined,\n  ).toMatchSnapshot();\n});\n"
  },
  {
    "path": "src/model/immutable/__tests__/ContentBlock-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst CharacterMetadata = require('CharacterMetadata');\nconst ContentBlock = require('ContentBlock');\nconst {BOLD} = require('SampleDraftInlineStyle');\n\nconst Immutable = require('immutable');\n\nconst ENTITY_KEY = 'x';\n\nconst getSampleBlock = () => {\n  return new ContentBlock({\n    key: 'a',\n    type: 'unstyled',\n    text: 'Alpha',\n    characterList: Immutable.List.of(\n      CharacterMetadata.create({style: BOLD, entity: ENTITY_KEY}),\n      CharacterMetadata.EMPTY,\n      CharacterMetadata.EMPTY,\n      CharacterMetadata.create({style: BOLD}),\n      CharacterMetadata.create({entity: ENTITY_KEY}),\n    ),\n  });\n};\n\ntest('must have appropriate default values', () => {\n  const text = 'Alpha';\n  const block = new ContentBlock({\n    key: 'a',\n    type: 'unstyled',\n    text,\n  });\n\n  expect(block.getKey()).toMatchSnapshot();\n  expect(block.getText()).toMatchSnapshot();\n  expect(block.getType()).toMatchSnapshot();\n  expect(block.getLength()).toMatchSnapshot();\n  expect(block.getCharacterList().count()).toMatchSnapshot();\n  expect(block.getCharacterList().toJS()).toMatchSnapshot();\n});\n\ntest('must provide default values', () => {\n  const block = new ContentBlock({});\n  expect(block.getType()).toMatchSnapshot();\n  expect(block.getText()).toMatchSnapshot();\n  expect(\n    Immutable.is(block.getCharacterList(), Immutable.List()),\n  ).toMatchSnapshot();\n});\n\ntest('must retrieve properties', () => {\n  const block = getSampleBlock();\n  expect(block.getKey()).toMatchSnapshot();\n  expect(block.getText()).toMatchSnapshot();\n  expect(block.getType()).toMatchSnapshot();\n  expect(block.getLength()).toMatchSnapshot();\n  expect(block.getCharacterList().count()).toMatchSnapshot();\n});\n\ntest('must properly retrieve style at offset', () => {\n  const block = getSampleBlock();\n\n  for (let i = 0; i <= 4; i++) {\n    expect(block.getInlineStyleAt(i).toJS()).toMatchSnapshot();\n  }\n});\n\ntest('must correctly identify ranges of styles', () => {\n  const block = getSampleBlock();\n  const cb = jest.fn();\n  block.findStyleRanges(() => true, cb);\n\n  expect(cb.mock.calls).toMatchSnapshot();\n});\n\ntest('must properly retrieve entity at offset', () => {\n  const block = getSampleBlock();\n\n  for (let i = 0; i <= 4; i++) {\n    expect(block.getEntityAt(i)).toMatchSnapshot();\n  }\n});\n\ntest('must correctly identify ranges of entities', () => {\n  const block = getSampleBlock();\n  const cb = jest.fn();\n  block.findEntityRanges(() => true, cb);\n\n  expect(cb.mock.calls).toMatchSnapshot();\n});\n"
  },
  {
    "path": "src/model/immutable/__tests__/ContentBlockNode-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst CharacterMetadata = require('CharacterMetadata');\nconst ContentBlockNode = require('ContentBlockNode');\nconst {BOLD, NONE} = require('SampleDraftInlineStyle');\n\nconst Immutable = require('immutable');\n\nconst entity_KEY = 'x';\n\nconst DEFAUL_BLOCK_CONFIG = {\n  key: 'a',\n  type: 'unstyled',\n  text: 'Alpha',\n  characterList: Immutable.List.of(\n    CharacterMetadata.create({style: BOLD, entity: entity_KEY}),\n    CharacterMetadata.EMPTY,\n    CharacterMetadata.EMPTY,\n    CharacterMetadata.create({style: BOLD}),\n    CharacterMetadata.create({entity: entity_KEY}),\n  ),\n};\n\nconst getSampleBlock = (props: void) => {\n  return new ContentBlockNode({\n    ...DEFAUL_BLOCK_CONFIG,\n    ...props,\n  });\n};\n\ntest('must have appropriate default values', () => {\n  const text = 'Alpha';\n  const block = new ContentBlockNode({\n    key: 'a',\n    type: 'unstyled',\n    text,\n  });\n\n  const characterList = Immutable.List(\n    Immutable.Repeat(CharacterMetadata.EMPTY, text.length),\n  );\n\n  expect(block.getKey()).toBe('a');\n  expect(block.getText()).toBe('Alpha');\n  expect(block.getType()).toBe('unstyled');\n  expect(block.getLength()).toBe(5);\n  expect(block.getCharacterList().count()).toBe(5);\n  expect(block.getCharacterList()).toEqual(characterList);\n});\n\ntest('must provide default values', () => {\n  const block = new ContentBlockNode();\n  expect(block.getType()).toBe('unstyled');\n  expect(block.getText()).toBe('');\n  expect(Immutable.is(block.getCharacterList(), Immutable.List())).toBe(true);\n});\n\ntest('must retrieve properties', () => {\n  const block = getSampleBlock();\n  expect(block.getKey()).toBe('a');\n  expect(block.getText()).toBe('Alpha');\n  expect(block.getType()).toBe('unstyled');\n  expect(block.getLength()).toBe(5);\n  expect(block.getCharacterList().count()).toBe(5);\n});\n\ntest('must properly retrieve style at offset', () => {\n  const block = getSampleBlock();\n  expect(block.getInlineStyleAt(0)).toBe(BOLD);\n  expect(block.getInlineStyleAt(1)).toBe(NONE);\n  expect(block.getInlineStyleAt(2)).toBe(NONE);\n  expect(block.getInlineStyleAt(3)).toBe(BOLD);\n  expect(block.getInlineStyleAt(4)).toBe(NONE);\n});\n\ntest('must correctly identify ranges of styles', () => {\n  const block = getSampleBlock();\n  const cb = jest.fn();\n  block.findStyleRanges(() => true, cb);\n\n  const calls = cb.mock.calls;\n  expect(calls.length).toBe(4);\n  expect(calls[0]).toEqual([0, 1]);\n  expect(calls[1]).toEqual([1, 3]);\n  expect(calls[2]).toEqual([3, 4]);\n  expect(calls[3]).toEqual([4, 5]);\n});\n\ntest('must properly retrieve entity at offset', () => {\n  const block = getSampleBlock();\n  expect(block.getEntityAt(0)).toBe(entity_KEY);\n  expect(block.getEntityAt(1)).toBe(null);\n  expect(block.getEntityAt(2)).toBe(null);\n  expect(block.getEntityAt(3)).toBe(null);\n  expect(block.getEntityAt(4)).toBe(entity_KEY);\n});\n\ntest('must correctly identify ranges of entities', () => {\n  const block = getSampleBlock();\n  const cb = jest.fn();\n  block.findEntityRanges(() => true, cb);\n\n  const calls = cb.mock.calls;\n  expect(calls.length).toBe(3);\n  expect(calls[0]).toEqual([0, 1]);\n  expect(calls[1]).toEqual([1, 4]);\n  expect(calls[2]).toEqual([4, 5]);\n});\n\ntest('must retrieve null when has no parent', () => {\n  const block = getSampleBlock();\n  expect(block.getParentKey()).toBe(null);\n});\n\ntest('must retrieve empty List when has no children', () => {\n  const block = getSampleBlock();\n  expect(block.getChildKeys()).toEqual(Immutable.List());\n});\n\ntest('must retrieve null when has no next sibbling', () => {\n  const block = getSampleBlock();\n  expect(block.getNextSiblingKey()).toBe(null);\n});\n\ntest('must retrieve null when has no previous sibbling', () => {\n  const block = getSampleBlock();\n  expect(block.getPrevSiblingKey()).toBe(null);\n});\n"
  },
  {
    "path": "src/model/immutable/__tests__/ContentState-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\nimport type {BlockNodeKey} from 'BlockNode';\nimport type CharacterMetadata from 'CharacterMetadata';\nimport type {DraftBlockType} from 'DraftBlockType';\nimport type {List, Map} from 'immutable';\n\nconst BlockMapBuilder = require('BlockMapBuilder');\nconst ContentBlock = require('ContentBlock');\nconst ContentState = require('ContentState');\nconst SelectionState = require('SelectionState');\n\njest.mock('SelectionState');\nlet contentState;\nconst SINGLE_BLOCK = [{text: 'Lorem ipsum', key: 'a'}];\nconst MULTI_BLOCK = [\n  {text: 'Four score', key: 'b'},\n  {text: 'and seven', key: 'c'},\n];\nconst ZERO_WIDTH_CHAR_BLOCK = [{text: unescape('%u200B%u200B'), key: 'a'}];\n\nconst createLink = () => {\n  return contentState.createEntity('LINK', 'MUTABLE', {uri: 'zombo.com'});\n};\n\nconst getSample = (\n  textBlocks: $TEMPORARY$array<\n    $TEMPORARY$object<{\n      characterList?: List<CharacterMetadata>,\n      data?: Map<$FlowFixMe, $FlowFixMe>,\n      depth?: number,\n      key?: BlockNodeKey,\n      text?: string,\n      type?: DraftBlockType,\n    }>,\n  >,\n) => {\n  const contentBlocks = textBlocks.map(block => new ContentBlock(block));\n  const blockMap = BlockMapBuilder.createFromArray(contentBlocks);\n  return new ContentState({\n    blockMap,\n    selectionBefore: new SelectionState(),\n    selectionAfter: new SelectionState(),\n  });\n};\n\nbeforeEach(() => {\n  contentState = ContentState.createFromText('');\n  jest.resetModules();\n});\n\ntest('must create a new instance', () => {\n  const state = getSample(SINGLE_BLOCK);\n  expect(state instanceof ContentState).toMatchSnapshot();\n});\n\ntest('must create properly with an empty block array', () => {\n  const state = ContentState.createFromBlockArray([]);\n  expect(state instanceof ContentState).toMatchSnapshot();\n});\n\ntest('key fetching must succeed or fail properly', () => {\n  const singleBlock = getSample(SINGLE_BLOCK);\n  const key = SINGLE_BLOCK[0].key;\n  const multiBlock = getSample(MULTI_BLOCK);\n  const firstKey = MULTI_BLOCK[0].key;\n  const secondKey = MULTI_BLOCK[1].key;\n\n  expect(singleBlock.getKeyAfter(key)).toMatchSnapshot();\n  expect(singleBlock.getKeyBefore(key)).toMatchSnapshot();\n  expect(singleBlock.getKeyAfter(key)).toMatchSnapshot();\n\n  expect(multiBlock.getKeyBefore(firstKey)).toMatchSnapshot();\n  expect(multiBlock.getKeyAfter(firstKey)).toMatchSnapshot();\n  expect(multiBlock.getKeyBefore(secondKey)).toMatchSnapshot();\n  expect(multiBlock.getKeyAfter(secondKey)).toMatchSnapshot();\n});\n\ntest('block fetching must retrieve or fail fetching block for key', () => {\n  const state = getSample(SINGLE_BLOCK);\n  const block = state.getBlockForKey('a');\n\n  expect(block instanceof ContentBlock).toMatchSnapshot();\n  expect(block.getText()).toMatchSnapshot();\n  expect(state.getBlockForKey('x')).toMatchSnapshot();\n});\n\ntest('must not include zero width chars for has text', () => {\n  expect(getSample(ZERO_WIDTH_CHAR_BLOCK).hasText()).toMatchSnapshot();\n  expect(getSample(SINGLE_BLOCK).hasText()).toMatchSnapshot();\n  expect(getSample(MULTI_BLOCK).hasText()).toMatchSnapshot();\n});\n\ntest('must create entities instances', () => {\n  const contentState = createLink();\n  expect(typeof contentState.getLastCreatedEntityKey()).toMatchSnapshot();\n});\n\ntest('must retrieve an entities instance given a key', () => {\n  const contentState = createLink();\n  const retrieved = contentState.getEntity(\n    contentState.getLastCreatedEntityKey(),\n  );\n  expect(retrieved.toJS()).toMatchSnapshot();\n});\n\ntest('must throw when retrieving entities for an invalid key', () => {\n  const contentState = createLink();\n  expect(() => contentState.getEntity('asdfzxcvqweriuop')).toThrow();\n});\n\ntest('must merge entities data', () => {\n  const contentState = createLink();\n  const key = contentState.getLastCreatedEntityKey();\n\n  // Merge new property.\n  const contentStateWithNewProp = contentState.mergeEntityData(key, {\n    foo: 'bar',\n  });\n  const updatedEntity = contentStateWithNewProp.getEntity(key);\n\n  // Replace existing property.\n  const contentStateWithUpdatedProp = contentStateWithNewProp.mergeEntityData(\n    key,\n    {uri: 'homestarrunner.com'},\n  );\n  const entityWithNewURI = contentStateWithUpdatedProp.getEntity(key);\n\n  expect(updatedEntity.getData()).toMatchSnapshot();\n  expect(entityWithNewURI.getData()).toMatchSnapshot();\n});\n\ntest('must replace entities data', () => {\n  const contentState = createLink();\n  const key = contentState.getLastCreatedEntityKey();\n\n  const updatedContentState = contentState.replaceEntityData(key, {\n    uri: 'something.com',\n    newProp: 'baz',\n  });\n  const entityWithReplacedData = updatedContentState.getEntity(key);\n\n  expect(entityWithReplacedData.getData()).toMatchSnapshot();\n});\n"
  },
  {
    "path": "src/model/immutable/__tests__/EditorBidiService-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst ContentBlock = require('ContentBlock');\nconst ContentState = require('ContentState');\nconst EditorBidiService = require('EditorBidiService');\n\nconst Immutable = require('immutable');\n\nconst {OrderedMap, Seq} = Immutable;\n\nconst ltr = new ContentBlock({\n  key: 'a',\n  text: 'hello',\n});\nconst rtl = new ContentBlock({\n  key: 'b',\n  text: '\\u05e9\\u05d1\\u05ea',\n});\nconst empty = new ContentBlock({\n  key: 'c',\n  text: '',\n});\n\nconst getContentState = (blocks: $TEMPORARY$array<ContentBlock>) => {\n  const keys = Seq(blocks.map(b => b.getKey()));\n  const values = Seq(blocks);\n  const blockMap = OrderedMap(keys.zip(values));\n  return new ContentState({blockMap});\n};\n\ntest('must create a new map', () => {\n  const state = getContentState([ltr]);\n  const directions = EditorBidiService.getDirectionMap(state);\n  expect(directions.toJS()).toMatchSnapshot();\n});\n\ntest('must return the same map if no changes', () => {\n  const state = getContentState([ltr]);\n  const directions = EditorBidiService.getDirectionMap(state);\n\n  const nextState = getContentState([ltr]);\n  const nextDirections = EditorBidiService.getDirectionMap(\n    nextState,\n    directions,\n  );\n\n  expect(state !== nextState).toMatchSnapshot();\n  expect(directions === nextDirections.toJS()).toMatchSnapshot();\n\n  expect(directions.toJS()).toMatchSnapshot();\n  expect(nextDirections.toJS()).toMatchSnapshot();\n});\n\ntest('must return the same map if no text changes', () => {\n  const state = getContentState([ltr]);\n  const directions = EditorBidiService.getDirectionMap(state);\n\n  const newLTR = new ContentBlock({\n    key: 'a',\n    text: 'hello',\n  });\n  expect(newLTR !== ltr).toMatchSnapshot();\n\n  const nextState = getContentState([newLTR]);\n  const nextDirections = EditorBidiService.getDirectionMap(\n    nextState,\n    directions,\n  );\n\n  expect(state !== nextState).toMatchSnapshot();\n  expect(directions === nextDirections.toJS()).toMatchSnapshot();\n\n  expect(directions.toJS()).toMatchSnapshot();\n  expect(nextDirections.toJS()).toMatchSnapshot();\n});\n\ntest('must return the same map if no directions change', () => {\n  const state = getContentState([ltr]);\n  const directions = EditorBidiService.getDirectionMap(state);\n\n  const newLTR = new ContentBlock({\n    key: 'a',\n    text: 'asdf',\n  });\n\n  const nextState = getContentState([newLTR]);\n  const nextDirections = EditorBidiService.getDirectionMap(\n    nextState,\n    directions,\n  );\n\n  expect(newLTR !== ltr).toMatchSnapshot();\n  expect(state !== nextState).toMatchSnapshot();\n  expect(directions === nextDirections.toJS()).toMatchSnapshot();\n\n  expect(directions.toJS()).toMatchSnapshot();\n  expect(nextDirections.toJS()).toMatchSnapshot();\n});\n\ntest('must return a new map if block keys change', () => {\n  const state = getContentState([ltr]);\n  const directions = EditorBidiService.getDirectionMap(state);\n\n  const newLTR = new ContentBlock({\n    key: 'asdf',\n    text: 'asdf',\n  });\n\n  const nextState = getContentState([newLTR]);\n  const nextDirections = EditorBidiService.getDirectionMap(\n    nextState,\n    directions,\n  );\n\n  expect(state !== nextState).toMatchSnapshot();\n  expect(directions !== nextDirections.toJS()).toMatchSnapshot();\n\n  expect(directions.toJS()).toMatchSnapshot();\n  expect(nextDirections.toJS()).toMatchSnapshot();\n});\n\ntest('must return a new map if direction changes', () => {\n  const state = getContentState([ltr, empty]);\n  const directions = EditorBidiService.getDirectionMap(state);\n  const nextState = getContentState([ltr, rtl]);\n  const nextDirections = EditorBidiService.getDirectionMap(\n    nextState,\n    directions,\n  );\n\n  expect(state !== nextState).toMatchSnapshot();\n  expect(directions !== nextDirections.toJS()).toMatchSnapshot();\n\n  expect(directions.toJS()).toMatchSnapshot();\n  expect(nextDirections.toJS()).toMatchSnapshot();\n});\n"
  },
  {
    "path": "src/model/immutable/__tests__/EditorState-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst CharacterMetadata = require('CharacterMetadata');\nconst ContentBlock = require('ContentBlock');\nconst ContentState = require('ContentState');\nconst DraftModifier = require('DraftModifier');\nconst EditorState = require('EditorState');\nconst RichTextEditorUtil = require('RichTextEditorUtil');\nconst {BOLD, ITALIC} = require('SampleDraftInlineStyle');\nconst SelectionState = require('SelectionState');\n\nconst Immutable = require('immutable');\n\nconst {List, Repeat} = Immutable;\n\nclass Decorator {}\nDecorator.prototype.getDecorations = jest.fn();\n\nconst DEFAULT_SELECTION = {\n  anchorKey: 'a',\n  anchorOffset: 0,\n  focusKey: 'a',\n  focusOffset: 0,\n  isBackward: false,\n};\n\nconst collapsedSelection = new SelectionState(DEFAULT_SELECTION);\nconst rangedSelection = new SelectionState({\n  ...DEFAULT_SELECTION,\n  focusOffset: 1,\n});\n\nconst plainBlock = new ContentBlock({\n  key: 'a',\n  text: 'Arsenal',\n});\nconst boldBlock = new ContentBlock({\n  key: 'b',\n  text: 'Burnley',\n  characterList: List(Repeat(CharacterMetadata.create({style: BOLD}), 7)),\n});\nconst boldA = List(Repeat('x', boldBlock.getLength()));\nconst emptyBlockA = new ContentBlock({\n  key: 'emptyA',\n  text: '',\n});\nconst emptyBlockB = new ContentBlock({\n  key: 'emptyB',\n  text: '',\n});\nconst italicBlock = new ContentBlock({\n  key: 'c',\n  text: 'Chelsea',\n  characterList: List(Repeat(CharacterMetadata.create({style: ITALIC}), 7)),\n});\n\nconst getSampleEditorState = (type, decorator) => {\n  switch (type) {\n    case 'DECORATED':\n      return EditorState.createWithContent(\n        ContentState.createFromBlockArray([boldBlock, italicBlock]),\n        decorator,\n      );\n    case 'MULTI_BLOCK':\n      return EditorState.createWithContent(\n        ContentState.createFromBlockArray([\n          emptyBlockA,\n          emptyBlockB,\n          boldBlock,\n        ]),\n      );\n    case 'UNDECORATED':\n    default:\n      return EditorState.createWithContent(\n        ContentState.createFromBlockArray([\n          plainBlock,\n          boldBlock,\n          emptyBlockA,\n          emptyBlockB,\n          italicBlock,\n        ]),\n      );\n  }\n};\n\nconst UNDECORATED_STATE = getSampleEditorState('UNDECORATED');\n\nconst MULTI_BLOCK_STATE = getSampleEditorState('MULTI_BLOCK');\n\nconst assertGetCurrentInlineStyle = (selection, state = UNDECORATED_STATE) => {\n  const editorState = EditorState.acceptSelection(state, selection);\n  expect(editorState.getCurrentInlineStyle().toJS()).toMatchSnapshot();\n};\n\nbeforeEach(() => {\n  Decorator.prototype.getDecorations.mockClear();\n  Decorator.prototype.getDecorations.mockImplementation((v, c) => {\n    return v === boldBlock ? boldA : List(Repeat(undefined, v.getLength()));\n  });\n});\n\ntest('uses right of the caret at document start', () => {\n  assertGetCurrentInlineStyle(collapsedSelection);\n});\n\ntest('uses left of the caret, at position `1+`', () => {\n  assertGetCurrentInlineStyle(\n    collapsedSelection.merge({\n      anchorOffset: 1,\n      focusOffset: 1,\n    }),\n  );\n});\n\ntest('uses right of the caret at offset `0` within document', () => {\n  assertGetCurrentInlineStyle(\n    collapsedSelection.merge({\n      anchorKey: 'b',\n      focusKey: 'b',\n    }),\n  );\n});\n\ntest('uses previous block at offset `0` within empty block', () => {\n  assertGetCurrentInlineStyle(\n    collapsedSelection.merge({\n      anchorKey: 'emptyA',\n      focusKey: 'emptyA',\n    }),\n  );\n});\n\ntest('looks upward through empty blocks to find a character with collapsed selection', () => {\n  assertGetCurrentInlineStyle(\n    collapsedSelection.merge({\n      anchorKey: 'emptyB',\n      focusKey: 'emptyB',\n    }),\n  );\n});\n\ntest('does not discard style override when changing block type', () => {\n  let editor = EditorState.createEmpty();\n\n  editor = RichTextEditorUtil.toggleInlineStyle(editor, 'BOLD');\n  editor = RichTextEditorUtil.toggleBlockType(editor, 'test-block');\n\n  expect(editor.getCurrentInlineStyle().toJS()).toMatchSnapshot();\n});\n\ntest('does not discard style override when adjusting depth', () => {\n  let editor = EditorState.createEmpty();\n\n  editor = RichTextEditorUtil.toggleInlineStyle(editor, 'BOLD');\n  editor = RichTextEditorUtil.onTab({preventDefault: () => {}}, editor);\n\n  expect(editor.getCurrentInlineStyle().toJS()).toMatchSnapshot();\n});\n\ntest('does not discard style override when splitting block', () => {\n  let editor = EditorState.createEmpty();\n\n  editor = RichTextEditorUtil.toggleInlineStyle(editor, 'BOLD');\n  editor = EditorState.push(\n    editor,\n    DraftModifier.splitBlock(editor.getCurrentContent(), editor.getSelection()),\n    'split-block',\n  );\n\n  expect(editor.getCurrentInlineStyle().toJS()).toMatchSnapshot();\n});\n\ntest('uses right of the start for blocks with text', () => {\n  assertGetCurrentInlineStyle(rangedSelection.set('focusKey', 'b'));\n});\n\ntest('uses left of the start if starting at end of block', () => {\n  const blockB = UNDECORATED_STATE.getCurrentContent().getBlockForKey('b');\n  assertGetCurrentInlineStyle(\n    collapsedSelection.merge({\n      anchorKey: 'b',\n      anchorOffset: blockB.getLength(),\n      focusKey: 'c',\n      focusOffset: 3,\n    }),\n  );\n});\n\ntest('looks upward through empty blocks to find a character', () => {\n  assertGetCurrentInlineStyle(\n    rangedSelection.merge({\n      anchorKey: 'emptyA',\n      anchorOffset: 0,\n      focusKey: 'c',\n      focusOffset: 3,\n    }),\n  );\n});\n\ntest('falls back to no style if in empty block at document start', () => {\n  assertGetCurrentInlineStyle(\n    new SelectionState({\n      anchorKey: 'emptyA',\n      anchorOffset: 0,\n      focusKey: 'c',\n      focusOffset: 3,\n      isBackward: false,\n    }),\n    MULTI_BLOCK_STATE,\n  );\n});\n\ntest('must set a new decorator', () => {\n  const decorator = new Decorator();\n  const editorState = getSampleEditorState('DECORATED', decorator);\n  const boldB = List(Repeat('y', boldBlock.getLength()));\n\n  expect(decorator.getDecorations.mock.calls.length).toMatchSnapshot();\n\n  Decorator.prototype.getDecorations.mockImplementation((v, c) => {\n    return v === boldBlock ? boldB : List(Repeat(undefined, v.getLength()));\n  });\n\n  class NextDecorator {}\n  NextDecorator.prototype.getDecorations = jest.fn();\n\n  const newDecorator = new NextDecorator();\n\n  NextDecorator.prototype.getDecorations.mockImplementation((v, c) => {\n    return v === boldBlock ? boldB : List(Repeat(undefined, v.getLength()));\n  });\n\n  const withNewDecorator = EditorState.set(editorState, {\n    decorator: newDecorator,\n  });\n\n  expect(withNewDecorator !== editorState).toMatchSnapshot();\n\n  // Twice for the initial tree map generation, then twice more for\n  // filter comparison.\n  expect(decorator.getDecorations.mock.calls.length).toMatchSnapshot();\n\n  // Twice for filter comparison, once for tree generation since one\n  // block has the same decoration list and is filtered out.\n  expect(newDecorator.getDecorations.mock.calls.length).toMatchSnapshot();\n\n  expect(withNewDecorator.getDecorator() === newDecorator).toMatchSnapshot();\n\n  // Preserve block trees that had the same decorator list.\n  expect(\n    editorState.getBlockTree(boldBlock.getKey()) ===\n      withNewDecorator.getBlockTree(boldBlock.getKey()),\n  ).toMatchSnapshot();\n\n  expect(\n    editorState.getBlockTree(italicBlock.getKey()) !==\n      withNewDecorator.getBlockTree(italicBlock.getKey()),\n  ).toMatchSnapshot();\n});\n\ntest('must call decorator with correct argument types and order', () => {\n  const decorator = new Decorator();\n  getSampleEditorState('DECORATED', decorator);\n  expect(decorator.getDecorations.mock.calls.length).toMatchSnapshot();\n});\n\ntest('must correctly remove a decorator', () => {\n  const decorator = new Decorator();\n  const editorState = getSampleEditorState('DECORATED', decorator);\n  const withNewDecorator = EditorState.set(editorState, {decorator: null});\n\n  expect(withNewDecorator !== editorState).toMatchSnapshot();\n  expect(decorator.getDecorations.mock.calls.length).toMatchSnapshot();\n  expect(withNewDecorator.getDecorator()).toMatchSnapshot();\n});\n"
  },
  {
    "path": "src/model/immutable/__tests__/SelectionState-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst SelectionState = require('SelectionState');\n\nconst DEFAULT_CONFIG = {\n  anchorKey: 'a',\n  anchorOffset: 0,\n  focusKey: 'a',\n  focusOffset: 0,\n  isBackward: false,\n  hasFocus: true,\n};\n\nconst flip = (selectionState: $FlowFixMe) => {\n  return selectionState.merge({\n    anchorKey: selectionState.getFocusKey(),\n    anchorOffset: selectionState.getFocusOffset(),\n    focusKey: selectionState.getAnchorKey(),\n    focusOffset: selectionState.getAnchorOffset(),\n    isBackward: !selectionState.getIsBackward(),\n  });\n};\n\nconst getSample = (\n  type:\n    | $TEMPORARY$string<'COLLAPSED'>\n    | $TEMPORARY$string<'MULTI_BLOCK'>\n    | $TEMPORARY$string<'WITHIN_BLOCK'>,\n  config:\n    | $TEMPORARY$object<{...}>\n    | $TEMPORARY$object<{anchorOffset: number, focusOffset: number}>\n    | $TEMPORARY$object<{isBackward: boolean}> = {},\n) => {\n  let selectionState;\n\n  switch (type) {\n    case 'MULTI_BLOCK':\n      selectionState = new SelectionState({\n        ...DEFAULT_CONFIG,\n        anchorKey: 'b',\n        focusKey: 'c',\n        anchorOffset: 10,\n        focusOffset: 15,\n        ...config,\n      });\n      break;\n    case 'WITHIN_BLOCK':\n      selectionState = new SelectionState({\n        ...DEFAULT_CONFIG,\n        anchorOffset: 10,\n        focusOffset: 20,\n        ...config,\n      });\n      break;\n    case 'COLLAPSED':\n    default:\n      selectionState = new SelectionState({\n        ...DEFAULT_CONFIG,\n        ...config,\n      });\n  }\n\n  expect(selectionState.toJS()).toMatchSnapshot();\n\n  return selectionState;\n};\n\nconst COLLAPSED = getSample('COLLAPSED');\nconst MULTI_BLOCK = getSample('MULTI_BLOCK');\nconst WITHIN_BLOCK = getSample('WITHIN_BLOCK');\n\ntest('must create a new instance', () => {\n  const state = COLLAPSED;\n  expect(state instanceof SelectionState).toBe(true);\n});\n\ntest('must retrieve properties correctly', () => {\n  const state = COLLAPSED;\n  expect([\n    state.getAnchorKey(),\n    state.getAnchorOffset(),\n    state.getFocusKey(),\n    state.getFocusOffset(),\n    state.getIsBackward(),\n    state.getHasFocus(),\n  ]).toMatchSnapshot();\n});\n\ntest('must serialize properties correctly', () => {\n  expect(COLLAPSED.serialize()).toMatchSnapshot();\n  expect(WITHIN_BLOCK.serialize()).toMatchSnapshot();\n  expect(MULTI_BLOCK.serialize()).toMatchSnapshot();\n});\n\ndescribe('hasEdgeWithin', () => {\n  test('is false for non-edge block keys', () => {\n    expect(COLLAPSED.hasEdgeWithin('b', 0, 0)).toBe(false);\n    expect(WITHIN_BLOCK.hasEdgeWithin('b', 0, 0)).toBe(false);\n    expect(MULTI_BLOCK.hasEdgeWithin('d', 0, 0)).toBe(false);\n  });\n\n  test('is false if offset is outside the selection range', () => {\n    expect(COLLAPSED.hasEdgeWithin('a', 1, 1)).toBe(false);\n    expect(WITHIN_BLOCK.hasEdgeWithin('a', 1, 1)).toBe(false);\n    expect(MULTI_BLOCK.hasEdgeWithin('b', 1, 1)).toBe(false);\n  });\n\n  test('is true if key match and offset equals selection edge', () => {\n    expect(COLLAPSED.hasEdgeWithin('a', 0, 1)).toBe(true);\n    expect(WITHIN_BLOCK.hasEdgeWithin('a', 10, 15)).toBe(true);\n    expect(WITHIN_BLOCK.hasEdgeWithin('a', 15, 20)).toBe(true);\n    expect(MULTI_BLOCK.hasEdgeWithin('b', 10, 20)).toBe(true);\n    expect(MULTI_BLOCK.hasEdgeWithin('c', 15, 20)).toBe(true);\n  });\n\n  test('is true if selection range is entirely within test range', () => {\n    expect(\n      getSample('COLLAPSED', {\n        anchorOffset: 5,\n        focusOffset: 5,\n      }).hasEdgeWithin('a', 0, 10),\n    ).toBe(true);\n    expect(WITHIN_BLOCK.hasEdgeWithin('a', 0, 40)).toBe(true);\n  });\n\n  test('is true if selection range edge overlaps test range', () => {\n    expect(WITHIN_BLOCK.hasEdgeWithin('a', 5, 15)).toBe(true);\n    expect(WITHIN_BLOCK.hasEdgeWithin('a', 15, 25)).toBe(true);\n    expect(MULTI_BLOCK.hasEdgeWithin('b', 5, 20)).toBe(true);\n    expect(MULTI_BLOCK.hasEdgeWithin('c', 5, 20)).toBe(true);\n  });\n\n  test('is false if test range is entirely within selection range', () => {\n    expect(WITHIN_BLOCK.hasEdgeWithin('a', 12, 15)).toBe(false);\n    expect(MULTI_BLOCK.hasEdgeWithin('b', 12, 15)).toBe(false);\n  });\n});\n\ntest('detects collapsed selection properly', () => {\n  expect(COLLAPSED.isCollapsed()).toBe(true);\n  expect(WITHIN_BLOCK.isCollapsed()).toBe(false);\n  expect(MULTI_BLOCK.isCollapsed()).toBe(false);\n});\n\ntest('properly identifies start and end keys', () => {\n  expect(COLLAPSED.getStartKey()).toMatchSnapshot();\n  expect(WITHIN_BLOCK.getStartKey()).toMatchSnapshot();\n  expect(MULTI_BLOCK.getStartKey()).toMatchSnapshot();\n  expect(COLLAPSED.getEndKey()).toMatchSnapshot();\n  expect(WITHIN_BLOCK.getEndKey()).toMatchSnapshot();\n  expect(MULTI_BLOCK.getEndKey()).toMatchSnapshot();\n});\n\ntest('properly identifies start and end offsets', () => {\n  expect(COLLAPSED.getStartOffset()).toMatchSnapshot();\n  expect(WITHIN_BLOCK.getStartOffset()).toMatchSnapshot();\n  expect(MULTI_BLOCK.getStartOffset()).toMatchSnapshot();\n  expect(COLLAPSED.getEndOffset()).toMatchSnapshot();\n  expect(WITHIN_BLOCK.getEndOffset()).toMatchSnapshot();\n  expect(MULTI_BLOCK.getEndOffset()).toMatchSnapshot();\n});\n\ntest('properly identifies start and end keys when backward', () => {\n  const withinBlock = flip(WITHIN_BLOCK);\n  const MULTI_BLOCK = getSample('MULTI_BLOCK', {\n    isBackward: true,\n  });\n\n  expect(withinBlock.getStartKey()).toMatchSnapshot();\n  expect(MULTI_BLOCK.getStartKey()).toMatchSnapshot();\n  expect(withinBlock.getEndKey()).toMatchSnapshot();\n  expect(MULTI_BLOCK.getEndKey()).toMatchSnapshot();\n});\n\ntest('properly identifies start and end offsets when backward', () => {\n  const withinBlock = flip(WITHIN_BLOCK);\n  const MULTI_BLOCK = getSample('MULTI_BLOCK', {\n    isBackward: true,\n  });\n\n  expect(withinBlock.getStartOffset()).toMatchSnapshot();\n  expect(MULTI_BLOCK.getStartOffset()).toMatchSnapshot();\n  expect(withinBlock.getEndOffset()).toMatchSnapshot();\n  expect(MULTI_BLOCK.getEndOffset()).toMatchSnapshot();\n});\n"
  },
  {
    "path": "src/model/immutable/__tests__/__snapshots__/BlockTree-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must generate for styled block with empty decorator 1`] = `\nArray [\n  Object {\n    \"decoratorKey\": null,\n    \"end\": 10,\n    \"leaves\": Array [\n      Object {\n        \"end\": 4,\n        \"start\": 0,\n      },\n      Object {\n        \"end\": 8,\n        \"start\": 4,\n      },\n      Object {\n        \"end\": 10,\n        \"start\": 8,\n      },\n    ],\n    \"start\": 0,\n  },\n]\n`;\n\nexports[`must generate for styled block with multiple decorators 1`] = `\nArray [\n  Object {\n    \"decoratorKey\": \"y\",\n    \"end\": 3,\n    \"leaves\": Array [\n      Object {\n        \"end\": 3,\n        \"start\": 0,\n      },\n    ],\n    \"start\": 0,\n  },\n  Object {\n    \"decoratorKey\": null,\n    \"end\": 6,\n    \"leaves\": Array [\n      Object {\n        \"end\": 4,\n        \"start\": 3,\n      },\n      Object {\n        \"end\": 6,\n        \"start\": 4,\n      },\n    ],\n    \"start\": 3,\n  },\n  Object {\n    \"decoratorKey\": \"z\",\n    \"end\": 10,\n    \"leaves\": Array [\n      Object {\n        \"end\": 8,\n        \"start\": 6,\n      },\n      Object {\n        \"end\": 10,\n        \"start\": 8,\n      },\n    ],\n    \"start\": 6,\n  },\n]\n`;\n\nexports[`must generate for styled block with single decorator 1`] = `\nArray [\n  Object {\n    \"decoratorKey\": null,\n    \"end\": 3,\n    \"leaves\": Array [\n      Object {\n        \"end\": 3,\n        \"start\": 0,\n      },\n    ],\n    \"start\": 0,\n  },\n  Object {\n    \"decoratorKey\": \"x\",\n    \"end\": 6,\n    \"leaves\": Array [\n      Object {\n        \"end\": 4,\n        \"start\": 3,\n      },\n      Object {\n        \"end\": 6,\n        \"start\": 4,\n      },\n    ],\n    \"start\": 3,\n  },\n  Object {\n    \"decoratorKey\": null,\n    \"end\": 10,\n    \"leaves\": Array [\n      Object {\n        \"end\": 8,\n        \"start\": 6,\n      },\n      Object {\n        \"end\": 10,\n        \"start\": 8,\n      },\n    ],\n    \"start\": 6,\n  },\n]\n`;\n\nexports[`must generate for unstyled block with empty decorator 1`] = `\nArray [\n  Object {\n    \"decoratorKey\": null,\n    \"end\": 7,\n    \"leaves\": Array [\n      Object {\n        \"end\": 7,\n        \"start\": 0,\n      },\n    ],\n    \"start\": 0,\n  },\n]\n`;\n\nexports[`must generate for unstyled block with multiple decorators 1`] = `\nArray [\n  Object {\n    \"decoratorKey\": \"y\",\n    \"end\": 3,\n    \"leaves\": Array [\n      Object {\n        \"end\": 3,\n        \"start\": 0,\n      },\n    ],\n    \"start\": 0,\n  },\n  Object {\n    \"decoratorKey\": null,\n    \"end\": 6,\n    \"leaves\": Array [\n      Object {\n        \"end\": 6,\n        \"start\": 3,\n      },\n    ],\n    \"start\": 3,\n  },\n  Object {\n    \"decoratorKey\": \"z\",\n    \"end\": 7,\n    \"leaves\": Array [\n      Object {\n        \"end\": 7,\n        \"start\": 6,\n      },\n    ],\n    \"start\": 6,\n  },\n]\n`;\n\nexports[`must generate for unstyled block with single decorator 1`] = `\nArray [\n  Object {\n    \"decoratorKey\": null,\n    \"end\": 3,\n    \"leaves\": Array [\n      Object {\n        \"end\": 3,\n        \"start\": 0,\n      },\n    ],\n    \"start\": 0,\n  },\n  Object {\n    \"decoratorKey\": \"x\",\n    \"end\": 6,\n    \"leaves\": Array [\n      Object {\n        \"end\": 6,\n        \"start\": 3,\n      },\n    ],\n    \"start\": 3,\n  },\n  Object {\n    \"decoratorKey\": null,\n    \"end\": 7,\n    \"leaves\": Array [\n      Object {\n        \"end\": 7,\n        \"start\": 6,\n      },\n    ],\n    \"start\": 6,\n  },\n]\n`;\n"
  },
  {
    "path": "src/model/immutable/__tests__/__snapshots__/CharacterMetadata-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must apply entity correctly 1`] = `\"x\"`;\n\nexports[`must apply entity correctly 2`] = `\"x\"`;\n\nexports[`must apply style 1`] = `true`;\n\nexports[`must apply style 2`] = `true`;\n\nexports[`must apply style 3`] = `true`;\n\nexports[`must have appropriate default values 1`] = `\nObject {\n  \"entity\": null,\n  \"style\": Array [],\n}\n`;\n\nexports[`must have appropriate default values 2`] = `0`;\n\nexports[`must have appropriate default values 3`] = `null`;\n\nexports[`must remove entity correctly 1`] = `null`;\n\nexports[`must remove entity correctly 2`] = `null`;\n\nexports[`must remove style 1`] = `true`;\n\nexports[`must remove style 2`] = `false`;\n\nexports[`must remove style 3`] = `false`;\n\nexports[`must remove style 4`] = `false`;\n\nexports[`must reuse objects by defaulting config properties 1`] = `true`;\n\nexports[`must reuse objects by defaulting config properties 2`] = `true`;\n\nexports[`must reuse objects by defaulting config properties 3`] = `true`;\n\nexports[`must reuse the same objects 1`] = `true`;\n\nexports[`must reuse the same objects 2`] = `true`;\n\nexports[`must reuse the same objects 3`] = `true`;\n\nexports[`must reuse the same objects 4`] = `true`;\n\nexports[`must reuse the same objects 5`] = `true`;\n\nexports[`must run \\`hasStyle\\` correctly 1`] = `false`;\n\nexports[`must run \\`hasStyle\\` correctly 2`] = `true`;\n\nexports[`must run \\`hasStyle\\` correctly 3`] = `true`;\n\nexports[`must run \\`hasStyle\\` correctly 4`] = `false`;\n\nexports[`must run \\`hasStyle\\` correctly 5`] = `false`;\n\nexports[`must run \\`hasStyle\\` correctly 6`] = `true`;\n"
  },
  {
    "path": "src/model/immutable/__tests__/__snapshots__/ContentBlock-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must correctly identify ranges of entities 1`] = `\nArray [\n  Array [\n    0,\n    1,\n  ],\n  Array [\n    1,\n    4,\n  ],\n  Array [\n    4,\n    5,\n  ],\n]\n`;\n\nexports[`must correctly identify ranges of styles 1`] = `\nArray [\n  Array [\n    0,\n    1,\n  ],\n  Array [\n    1,\n    3,\n  ],\n  Array [\n    3,\n    4,\n  ],\n  Array [\n    4,\n    5,\n  ],\n]\n`;\n\nexports[`must have appropriate default values 1`] = `\"a\"`;\n\nexports[`must have appropriate default values 2`] = `\"Alpha\"`;\n\nexports[`must have appropriate default values 3`] = `\"unstyled\"`;\n\nexports[`must have appropriate default values 4`] = `5`;\n\nexports[`must have appropriate default values 5`] = `5`;\n\nexports[`must have appropriate default values 6`] = `\nArray [\n  Object {\n    \"entity\": null,\n    \"style\": Array [],\n  },\n  Object {\n    \"entity\": null,\n    \"style\": Array [],\n  },\n  Object {\n    \"entity\": null,\n    \"style\": Array [],\n  },\n  Object {\n    \"entity\": null,\n    \"style\": Array [],\n  },\n  Object {\n    \"entity\": null,\n    \"style\": Array [],\n  },\n]\n`;\n\nexports[`must properly retrieve entity at offset 1`] = `\"x\"`;\n\nexports[`must properly retrieve entity at offset 2`] = `null`;\n\nexports[`must properly retrieve entity at offset 3`] = `null`;\n\nexports[`must properly retrieve entity at offset 4`] = `null`;\n\nexports[`must properly retrieve entity at offset 5`] = `\"x\"`;\n\nexports[`must properly retrieve style at offset 1`] = `\nArray [\n  \"BOLD\",\n]\n`;\n\nexports[`must properly retrieve style at offset 2`] = `Array []`;\n\nexports[`must properly retrieve style at offset 3`] = `Array []`;\n\nexports[`must properly retrieve style at offset 4`] = `\nArray [\n  \"BOLD\",\n]\n`;\n\nexports[`must properly retrieve style at offset 5`] = `Array []`;\n\nexports[`must provide default values 1`] = `\"unstyled\"`;\n\nexports[`must provide default values 2`] = `\"\"`;\n\nexports[`must provide default values 3`] = `true`;\n\nexports[`must retrieve properties 1`] = `\"a\"`;\n\nexports[`must retrieve properties 2`] = `\"Alpha\"`;\n\nexports[`must retrieve properties 3`] = `\"unstyled\"`;\n\nexports[`must retrieve properties 4`] = `5`;\n\nexports[`must retrieve properties 5`] = `5`;\n"
  },
  {
    "path": "src/model/immutable/__tests__/__snapshots__/ContentState-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`block fetching must retrieve or fail fetching block for key 1`] = `true`;\n\nexports[`block fetching must retrieve or fail fetching block for key 2`] = `\"Lorem ipsum\"`;\n\nexports[`block fetching must retrieve or fail fetching block for key 3`] = `undefined`;\n\nexports[`key fetching must succeed or fail properly 1`] = `undefined`;\n\nexports[`key fetching must succeed or fail properly 2`] = `undefined`;\n\nexports[`key fetching must succeed or fail properly 3`] = `undefined`;\n\nexports[`key fetching must succeed or fail properly 4`] = `undefined`;\n\nexports[`key fetching must succeed or fail properly 5`] = `\"c\"`;\n\nexports[`key fetching must succeed or fail properly 6`] = `\"b\"`;\n\nexports[`key fetching must succeed or fail properly 7`] = `undefined`;\n\nexports[`must create a new instance 1`] = `true`;\n\nexports[`must create entities instances 1`] = `\"string\"`;\n\nexports[`must create properly with an empty block array 1`] = `true`;\n\nexports[`must merge entities data 1`] = `\nObject {\n  \"foo\": \"bar\",\n  \"uri\": \"zombo.com\",\n}\n`;\n\nexports[`must merge entities data 2`] = `\nObject {\n  \"foo\": \"bar\",\n  \"uri\": \"homestarrunner.com\",\n}\n`;\n\nexports[`must not include zero width chars for has text 1`] = `false`;\n\nexports[`must not include zero width chars for has text 2`] = `true`;\n\nexports[`must not include zero width chars for has text 3`] = `true`;\n\nexports[`must replace entities data 1`] = `\nObject {\n  \"newProp\": \"baz\",\n  \"uri\": \"something.com\",\n}\n`;\n\nexports[`must retrieve an entities instance given a key 1`] = `\nObject {\n  \"data\": Object {\n    \"uri\": \"zombo.com\",\n  },\n  \"mutability\": \"MUTABLE\",\n  \"type\": \"LINK\",\n}\n`;\n"
  },
  {
    "path": "src/model/immutable/__tests__/__snapshots__/EditorBidiService-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must create a new map 1`] = `\nObject {\n  \"a\": \"LTR\",\n}\n`;\n\nexports[`must return a new map if block keys change 1`] = `true`;\n\nexports[`must return a new map if block keys change 2`] = `true`;\n\nexports[`must return a new map if block keys change 3`] = `\nObject {\n  \"a\": \"LTR\",\n}\n`;\n\nexports[`must return a new map if block keys change 4`] = `\nObject {\n  \"asdf\": \"LTR\",\n}\n`;\n\nexports[`must return a new map if direction changes 1`] = `true`;\n\nexports[`must return a new map if direction changes 2`] = `true`;\n\nexports[`must return a new map if direction changes 3`] = `\nObject {\n  \"a\": \"LTR\",\n  \"c\": \"LTR\",\n}\n`;\n\nexports[`must return a new map if direction changes 4`] = `\nObject {\n  \"a\": \"LTR\",\n  \"b\": \"RTL\",\n}\n`;\n\nexports[`must return the same map if no changes 1`] = `true`;\n\nexports[`must return the same map if no changes 2`] = `false`;\n\nexports[`must return the same map if no changes 3`] = `\nObject {\n  \"a\": \"LTR\",\n}\n`;\n\nexports[`must return the same map if no changes 4`] = `\nObject {\n  \"a\": \"LTR\",\n}\n`;\n\nexports[`must return the same map if no directions change 1`] = `true`;\n\nexports[`must return the same map if no directions change 2`] = `true`;\n\nexports[`must return the same map if no directions change 3`] = `false`;\n\nexports[`must return the same map if no directions change 4`] = `\nObject {\n  \"a\": \"LTR\",\n}\n`;\n\nexports[`must return the same map if no directions change 5`] = `\nObject {\n  \"a\": \"LTR\",\n}\n`;\n\nexports[`must return the same map if no text changes 1`] = `true`;\n\nexports[`must return the same map if no text changes 2`] = `true`;\n\nexports[`must return the same map if no text changes 3`] = `false`;\n\nexports[`must return the same map if no text changes 4`] = `\nObject {\n  \"a\": \"LTR\",\n}\n`;\n\nexports[`must return the same map if no text changes 5`] = `\nObject {\n  \"a\": \"LTR\",\n}\n`;\n"
  },
  {
    "path": "src/model/immutable/__tests__/__snapshots__/EditorState-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`does not discard style override when adjusting depth 1`] = `\nArray [\n  \"BOLD\",\n]\n`;\n\nexports[`does not discard style override when changing block type 1`] = `\nArray [\n  \"BOLD\",\n]\n`;\n\nexports[`does not discard style override when splitting block 1`] = `\nArray [\n  \"BOLD\",\n]\n`;\n\nexports[`falls back to no style if in empty block at document start 1`] = `Array []`;\n\nexports[`looks upward through empty blocks to find a character 1`] = `\nArray [\n  \"BOLD\",\n]\n`;\n\nexports[`looks upward through empty blocks to find a character with collapsed selection 1`] = `\nArray [\n  \"BOLD\",\n]\n`;\n\nexports[`must call decorator with correct argument types and order 1`] = `2`;\n\nexports[`must correctly remove a decorator 1`] = `true`;\n\nexports[`must correctly remove a decorator 2`] = `2`;\n\nexports[`must correctly remove a decorator 3`] = `null`;\n\nexports[`must set a new decorator 1`] = `2`;\n\nexports[`must set a new decorator 2`] = `true`;\n\nexports[`must set a new decorator 3`] = `4`;\n\nexports[`must set a new decorator 4`] = `3`;\n\nexports[`must set a new decorator 5`] = `true`;\n\nexports[`must set a new decorator 6`] = `true`;\n\nexports[`must set a new decorator 7`] = `true`;\n\nexports[`uses left of the caret, at position \\`1+\\` 1`] = `Array []`;\n\nexports[`uses left of the start if starting at end of block 1`] = `\nArray [\n  \"BOLD\",\n]\n`;\n\nexports[`uses previous block at offset \\`0\\` within empty block 1`] = `\nArray [\n  \"BOLD\",\n]\n`;\n\nexports[`uses right of the caret at document start 1`] = `Array []`;\n\nexports[`uses right of the caret at offset \\`0\\` within document 1`] = `\nArray [\n  \"BOLD\",\n]\n`;\n\nexports[`uses right of the start for blocks with text 1`] = `Array []`;\n"
  },
  {
    "path": "src/model/immutable/__tests__/__snapshots__/SelectionState-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[` 1`] = `\nObject {\n  \"anchorKey\": \"a\",\n  \"anchorOffset\": 0,\n  \"focusKey\": \"a\",\n  \"focusOffset\": 0,\n  \"hasFocus\": true,\n  \"isBackward\": false,\n}\n`;\n\nexports[` 2`] = `\nObject {\n  \"anchorKey\": \"b\",\n  \"anchorOffset\": 10,\n  \"focusKey\": \"c\",\n  \"focusOffset\": 15,\n  \"hasFocus\": true,\n  \"isBackward\": false,\n}\n`;\n\nexports[` 3`] = `\nObject {\n  \"anchorKey\": \"a\",\n  \"anchorOffset\": 10,\n  \"focusKey\": \"a\",\n  \"focusOffset\": 20,\n  \"hasFocus\": true,\n  \"isBackward\": false,\n}\n`;\n\nexports[`hasEdgeWithin is true if selection range is entirely within test range 1`] = `\nObject {\n  \"anchorKey\": \"a\",\n  \"anchorOffset\": 5,\n  \"focusKey\": \"a\",\n  \"focusOffset\": 5,\n  \"hasFocus\": true,\n  \"isBackward\": false,\n}\n`;\n\nexports[`must retrieve properties correctly 1`] = `\nArray [\n  \"a\",\n  0,\n  \"a\",\n  0,\n  false,\n  true,\n]\n`;\n\nexports[`must serialize properties correctly 1`] = `\"Anchor: a:0, Focus: a:0, Is Backward: false, Has Focus: true\"`;\n\nexports[`must serialize properties correctly 2`] = `\"Anchor: a:10, Focus: a:20, Is Backward: false, Has Focus: true\"`;\n\nexports[`must serialize properties correctly 3`] = `\"Anchor: b:10, Focus: c:15, Is Backward: false, Has Focus: true\"`;\n\nexports[`properly identifies start and end keys 1`] = `\"a\"`;\n\nexports[`properly identifies start and end keys 2`] = `\"a\"`;\n\nexports[`properly identifies start and end keys 3`] = `\"b\"`;\n\nexports[`properly identifies start and end keys 4`] = `\"a\"`;\n\nexports[`properly identifies start and end keys 5`] = `\"a\"`;\n\nexports[`properly identifies start and end keys 6`] = `\"c\"`;\n\nexports[`properly identifies start and end keys when backward 1`] = `\nObject {\n  \"anchorKey\": \"b\",\n  \"anchorOffset\": 10,\n  \"focusKey\": \"c\",\n  \"focusOffset\": 15,\n  \"hasFocus\": true,\n  \"isBackward\": true,\n}\n`;\n\nexports[`properly identifies start and end keys when backward 2`] = `\"a\"`;\n\nexports[`properly identifies start and end keys when backward 3`] = `\"c\"`;\n\nexports[`properly identifies start and end keys when backward 4`] = `\"a\"`;\n\nexports[`properly identifies start and end keys when backward 5`] = `\"b\"`;\n\nexports[`properly identifies start and end offsets 1`] = `0`;\n\nexports[`properly identifies start and end offsets 2`] = `10`;\n\nexports[`properly identifies start and end offsets 3`] = `10`;\n\nexports[`properly identifies start and end offsets 4`] = `0`;\n\nexports[`properly identifies start and end offsets 5`] = `20`;\n\nexports[`properly identifies start and end offsets 6`] = `15`;\n\nexports[`properly identifies start and end offsets when backward 1`] = `\nObject {\n  \"anchorKey\": \"b\",\n  \"anchorOffset\": 10,\n  \"focusKey\": \"c\",\n  \"focusOffset\": 15,\n  \"hasFocus\": true,\n  \"isBackward\": true,\n}\n`;\n\nexports[`properly identifies start and end offsets when backward 2`] = `10`;\n\nexports[`properly identifies start and end offsets when backward 3`] = `15`;\n\nexports[`properly identifies start and end offsets when backward 4`] = `20`;\n\nexports[`properly identifies start and end offsets when backward 5`] = `10`;\n"
  },
  {
    "path": "src/model/immutable/__tests__/__snapshots__/findRangesImmutable-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must be a no-op for an empty list 1`] = `Array []`;\n\nexports[`must identify each range 1`] = `\nArray [\n  Array [\n    0,\n    2,\n  ],\n  Array [\n    2,\n    4,\n  ],\n  Array [\n    4,\n    6,\n  ],\n  Array [\n    6,\n    8,\n  ],\n]\n`;\n\nexports[`must identify the full list as a single range 1`] = `\nArray [\n  Array [\n    0,\n    5,\n  ],\n]\n`;\n\nexports[`must properly use \\`areEqualFn\\` 1`] = `\nArray [\n  Array [\n    0,\n    1,\n  ],\n  Array [\n    1,\n    2,\n  ],\n  Array [\n    2,\n    3,\n  ],\n  Array [\n    3,\n    4,\n  ],\n  Array [\n    4,\n    5,\n  ],\n]\n`;\n\nexports[`must properly use \\`filterFn\\` 1`] = `Array []`;\n"
  },
  {
    "path": "src/model/immutable/__tests__/findRangesImmutable-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {List as $IMPORTED_TYPE$_List} from 'immutable';\n\nconst findRangesImmutable = require('findRangesImmutable');\nconst Immutable = require('immutable');\n\nconst {List} = Immutable;\n\nconst returnTrue = () => true;\n\nconst SAMPLE_LIST = List.of(1, 1, 1, 1, 1);\n\nconst assertFindRangesImmutable = (\n  list: $IMPORTED_TYPE$_List<number>,\n  areEqualFn: (a: number, b: number) => boolean = returnTrue,\n  filterFn: () => boolean = returnTrue,\n  foundFn: JestMockFn<Array<number>, void> = jest.fn(),\n) => {\n  findRangesImmutable(list, areEqualFn, filterFn, foundFn);\n  expect(foundFn.mock.calls).toMatchSnapshot();\n};\n\ntest('must be a no-op for an empty list', () => {\n  assertFindRangesImmutable(List());\n});\n\ntest('must identify the full list as a single range', () => {\n  assertFindRangesImmutable(SAMPLE_LIST);\n});\n\ntest('must properly use `areEqualFn`', () => {\n  // never equal\n  assertFindRangesImmutable(SAMPLE_LIST, () => false);\n});\n\ntest('must properly use `filterFn`', () => {\n  // never an accepted filter result\n  assertFindRangesImmutable(SAMPLE_LIST, returnTrue, () => false);\n});\n\ntest('must identify each range', () => {\n  assertFindRangesImmutable(\n    List.of(0, 0, 1, 1, 0, 0, 2, 2),\n    (a, b) => a === b,\n    returnTrue,\n  );\n});\n"
  },
  {
    "path": "src/model/immutable/findRangesImmutable.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {List} from 'immutable';\n\n/**\n * Search through an array to find contiguous stretches of elements that\n * match a specified filter function.\n *\n * When ranges are found, execute a specified `found` function to supply\n * the values to the caller.\n */\nfunction findRangesImmutable<T>(\n  haystack: List<T>,\n  areEqualFn: (a: T, b: T) => boolean,\n  filterFn: (value: T) => boolean,\n  foundFn: (start: number, end: number) => void,\n): void {\n  if (!haystack.size) {\n    return;\n  }\n\n  let cursor: number = 0;\n\n  haystack.reduce((value: T, nextValue, nextIndex) => {\n    if (!areEqualFn(value, nextValue)) {\n      if (filterFn(value)) {\n        foundFn(cursor, nextIndex);\n      }\n      cursor = nextIndex;\n    }\n    return nextValue;\n  });\n\n  filterFn(haystack.last()) && foundFn(cursor, haystack.count());\n}\n\nmodule.exports = findRangesImmutable;\n"
  },
  {
    "path": "src/model/keys/generateRandomKey.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst seenKeys: {[string]: boolean} = {};\nconst MULTIPLIER = Math.pow(2, 24);\n\nfunction generateRandomKey(): string {\n  let key;\n  while (key === undefined || seenKeys.hasOwnProperty(key) || !isNaN(+key)) {\n    key = Math.floor(Math.random() * MULTIPLIER).toString(32);\n  }\n  seenKeys[key] = true;\n  return key;\n}\n\nmodule.exports = generateRandomKey;\n"
  },
  {
    "path": "src/model/keys/mockUUID.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nlet counter = 0;\n\nfunction mockUUID(): string {\n  return '' + ++counter;\n}\n\nmodule.exports = mockUUID;\n"
  },
  {
    "path": "src/model/modifier/AtomicBlockUtils.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type {DraftInsertionType} from 'DraftInsertionType';\nimport type SelectionState from 'SelectionState';\n\nconst BlockMapBuilder = require('BlockMapBuilder');\nconst CharacterMetadata = require('CharacterMetadata');\nconst ContentBlock = require('ContentBlock');\nconst ContentBlockNode = require('ContentBlockNode');\nconst DraftModifier = require('DraftModifier');\nconst EditorState = require('EditorState');\n\nconst generateRandomKey = require('generateRandomKey');\nconst gkx = require('gkx');\nconst Immutable = require('immutable');\nconst moveBlockInContentState = require('moveBlockInContentState');\n\nconst experimentalTreeDataSupport = gkx('draft_tree_data_support');\nconst ContentBlockRecord = experimentalTreeDataSupport\n  ? ContentBlockNode\n  : ContentBlock;\n\nconst {List, Repeat} = Immutable;\n\nconst AtomicBlockUtils = {\n  insertAtomicBlock(\n    editorState: EditorState,\n    entityKey: string,\n    character: string,\n  ): EditorState {\n    const contentState = editorState.getCurrentContent();\n    const selectionState = editorState.getSelection();\n\n    const afterRemoval = DraftModifier.removeRange(\n      contentState,\n      selectionState,\n      'backward',\n    );\n\n    const targetSelection = afterRemoval.getSelectionAfter();\n    const afterSplit = DraftModifier.splitBlock(afterRemoval, targetSelection);\n    const insertionTarget = afterSplit.getSelectionAfter();\n\n    const asAtomicBlock = DraftModifier.setBlockType(\n      afterSplit,\n      insertionTarget,\n      'atomic',\n    );\n\n    const charData = CharacterMetadata.create({entity: entityKey});\n\n    let atomicBlockConfig = {\n      key: generateRandomKey(),\n      type: 'atomic',\n      text: character,\n      characterList: List(Repeat(charData, character.length)),\n    };\n\n    let atomicDividerBlockConfig = {\n      key: generateRandomKey(),\n      type: 'unstyled',\n    };\n\n    if (experimentalTreeDataSupport) {\n      atomicBlockConfig = {\n        ...atomicBlockConfig,\n        nextSibling: atomicDividerBlockConfig.key,\n      };\n      atomicDividerBlockConfig = {\n        ...atomicDividerBlockConfig,\n        prevSibling: atomicBlockConfig.key,\n      };\n    }\n\n    const fragmentArray = [\n      new ContentBlockRecord(atomicBlockConfig),\n      new ContentBlockRecord(atomicDividerBlockConfig),\n    ];\n\n    const fragment = BlockMapBuilder.createFromArray(fragmentArray);\n\n    const withAtomicBlock = DraftModifier.replaceWithFragment(\n      asAtomicBlock,\n      insertionTarget,\n      fragment,\n    );\n\n    const newContent = withAtomicBlock.merge({\n      selectionBefore: selectionState,\n      selectionAfter: withAtomicBlock.getSelectionAfter().set('hasFocus', true),\n    });\n\n    return EditorState.push(editorState, newContent, 'insert-fragment');\n  },\n\n  moveAtomicBlock(\n    editorState: EditorState,\n    atomicBlock: BlockNodeRecord,\n    targetRange: SelectionState,\n    insertionMode?: DraftInsertionType,\n  ): EditorState {\n    const contentState = editorState.getCurrentContent();\n    const selectionState = editorState.getSelection();\n\n    let withMovedAtomicBlock;\n\n    if (insertionMode === 'before' || insertionMode === 'after') {\n      const targetBlock = contentState.getBlockForKey(\n        insertionMode === 'before'\n          ? targetRange.getStartKey()\n          : targetRange.getEndKey(),\n      );\n\n      withMovedAtomicBlock = moveBlockInContentState(\n        contentState,\n        atomicBlock,\n        targetBlock,\n        insertionMode,\n      );\n    } else {\n      const afterRemoval = DraftModifier.removeRange(\n        contentState,\n        targetRange,\n        'backward',\n      );\n\n      const selectionAfterRemoval = afterRemoval.getSelectionAfter();\n      const targetBlock = afterRemoval.getBlockForKey(\n        selectionAfterRemoval.getFocusKey(),\n      );\n\n      if (selectionAfterRemoval.getStartOffset() === 0) {\n        withMovedAtomicBlock = moveBlockInContentState(\n          afterRemoval,\n          atomicBlock,\n          targetBlock,\n          'before',\n        );\n      } else if (\n        selectionAfterRemoval.getEndOffset() === targetBlock.getLength()\n      ) {\n        withMovedAtomicBlock = moveBlockInContentState(\n          afterRemoval,\n          atomicBlock,\n          targetBlock,\n          'after',\n        );\n      } else {\n        const afterSplit = DraftModifier.splitBlock(\n          afterRemoval,\n          selectionAfterRemoval,\n        );\n\n        const selectionAfterSplit = afterSplit.getSelectionAfter();\n        const targetBlock = afterSplit.getBlockForKey(\n          selectionAfterSplit.getFocusKey(),\n        );\n\n        withMovedAtomicBlock = moveBlockInContentState(\n          afterSplit,\n          atomicBlock,\n          targetBlock,\n          'before',\n        );\n      }\n    }\n\n    const newContent = withMovedAtomicBlock.merge({\n      selectionBefore: selectionState,\n      selectionAfter: withMovedAtomicBlock\n        .getSelectionAfter()\n        .set('hasFocus', true),\n    });\n\n    return EditorState.push(editorState, newContent, 'move-block');\n  },\n};\n\nmodule.exports = AtomicBlockUtils;\n"
  },
  {
    "path": "src/model/modifier/DraftEntitySegments.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {DraftRange} from 'DraftRange';\nimport type {DraftRemovalDirection} from 'DraftRemovalDirection';\n\n/**\n * Identify the range to delete from a segmented entity.\n *\n * Rules:\n *\n *  Example: 'John F. Kennedy'\n *\n *   - Deletion from within any non-whitespace (i.e. ['John', 'F.', 'Kennedy'])\n *     will return the range of that text.\n *\n *       'John F. Kennedy' -> 'John F.'\n *                  ^\n *\n *   - Forward deletion of whitespace will remove the following section:\n *\n *       'John F. Kennedy' -> 'John Kennedy'\n *            ^\n *\n *   - Backward deletion of whitespace will remove the previous section:\n *\n *       'John F. Kennedy' -> 'F. Kennedy'\n *            ^\n */\nconst DraftEntitySegments = {\n  getRemovalRange(\n    selectionStart: number,\n    selectionEnd: number,\n    text: string,\n    entityStart: number,\n    direction: DraftRemovalDirection,\n  ): DraftRange {\n    let segments = text.split(' ');\n    segments = segments.map((/*string*/ segment, /*number*/ ii) => {\n      if (direction === 'forward') {\n        if (ii > 0) {\n          return ' ' + segment;\n        }\n      } else if (ii < segments.length - 1) {\n        return segment + ' ';\n      }\n      return segment;\n    });\n\n    let segmentStart = entityStart;\n    let segmentEnd;\n    let segment;\n    let removalStart: any = null;\n    let removalEnd: any = null;\n\n    for (let jj = 0; jj < segments.length; jj++) {\n      segment = segments[jj];\n      segmentEnd = segmentStart + segment.length;\n\n      // Our selection overlaps this segment.\n      if (selectionStart < segmentEnd && segmentStart < selectionEnd) {\n        if (removalStart !== null) {\n          removalEnd = segmentEnd;\n        } else {\n          removalStart = segmentStart;\n          removalEnd = segmentEnd;\n        }\n      } else if (removalStart !== null) {\n        break;\n      }\n\n      segmentStart = segmentEnd;\n    }\n\n    const entityEnd = entityStart + text.length;\n    const atStart = removalStart === entityStart;\n    const atEnd = removalEnd === entityEnd;\n\n    if ((!atStart && atEnd) || (atStart && !atEnd)) {\n      if (direction === 'forward') {\n        if (removalEnd !== entityEnd) {\n          removalEnd++;\n        }\n      } else if (removalStart !== entityStart) {\n        removalStart--;\n      }\n    }\n\n    return {\n      start: removalStart,\n      end: removalEnd,\n    };\n  },\n};\n\nmodule.exports = DraftEntitySegments;\n"
  },
  {
    "path": "src/model/modifier/DraftModifier.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockMap} from 'BlockMap';\nimport type ContentState from 'ContentState';\nimport type {DraftBlockType} from 'DraftBlockType';\nimport type {DraftInlineStyle} from 'DraftInlineStyle';\nimport type {DraftRemovalDirection} from 'DraftRemovalDirection';\nimport type SelectionState from 'SelectionState';\nimport type {Map} from 'immutable';\nimport type {BlockDataMergeBehavior} from 'insertFragmentIntoContentState';\n\nconst CharacterMetadata = require('CharacterMetadata');\nconst ContentStateInlineStyle = require('ContentStateInlineStyle');\n\nconst applyEntityToContentState = require('applyEntityToContentState');\nconst getCharacterRemovalRange = require('getCharacterRemovalRange');\nconst getContentStateFragment = require('getContentStateFragment');\nconst Immutable = require('immutable');\nconst insertFragmentIntoContentState = require('insertFragmentIntoContentState');\nconst insertTextIntoContentState = require('insertTextIntoContentState');\nconst invariant = require('invariant');\nconst modifyBlockForContentState = require('modifyBlockForContentState');\nconst removeEntitiesAtEdges = require('removeEntitiesAtEdges');\nconst removeRangeFromContentState = require('removeRangeFromContentState');\nconst splitBlockInContentState = require('splitBlockInContentState');\n\nconst {OrderedSet} = Immutable;\n\n/**\n * `DraftModifier` provides a set of convenience methods that apply\n * modifications to a `ContentState` object based on a target `SelectionState`.\n *\n * Any change to a `ContentState` should be decomposable into a series of\n * transaction functions that apply the required changes and return output\n * `ContentState` objects.\n *\n * These functions encapsulate some of the most common transaction sequences.\n */\nconst DraftModifier = {\n  replaceText(\n    contentState: ContentState,\n    rangeToReplace: SelectionState,\n    text: string,\n    inlineStyle?: DraftInlineStyle,\n    entityKey?: ?string,\n  ): ContentState {\n    const withoutEntities = removeEntitiesAtEdges(contentState, rangeToReplace);\n    const withoutText = removeRangeFromContentState(\n      withoutEntities,\n      rangeToReplace,\n    );\n\n    const character = CharacterMetadata.create({\n      style: inlineStyle || OrderedSet(),\n      entity: entityKey || null,\n    });\n\n    return insertTextIntoContentState(\n      withoutText,\n      withoutText.getSelectionAfter(),\n      text,\n      character,\n    );\n  },\n\n  insertText(\n    contentState: ContentState,\n    targetRange: SelectionState,\n    text: string,\n    inlineStyle?: DraftInlineStyle,\n    entityKey?: ?string,\n  ): ContentState {\n    invariant(\n      targetRange.isCollapsed(),\n      'Target range must be collapsed for `insertText`.',\n    );\n    return DraftModifier.replaceText(\n      contentState,\n      targetRange,\n      text,\n      inlineStyle,\n      entityKey,\n    );\n  },\n\n  moveText(\n    contentState: ContentState,\n    removalRange: SelectionState,\n    targetRange: SelectionState,\n  ): ContentState {\n    const movedFragment = getContentStateFragment(contentState, removalRange);\n\n    const afterRemoval = DraftModifier.removeRange(\n      contentState,\n      removalRange,\n      'backward',\n    );\n\n    return DraftModifier.replaceWithFragment(\n      afterRemoval,\n      targetRange,\n      movedFragment,\n    );\n  },\n\n  replaceWithFragment(\n    contentState: ContentState,\n    targetRange: SelectionState,\n    fragment: BlockMap,\n    mergeBlockData?: BlockDataMergeBehavior = 'REPLACE_WITH_NEW_DATA',\n  ): ContentState {\n    const withoutEntities = removeEntitiesAtEdges(contentState, targetRange);\n    const withoutText = removeRangeFromContentState(\n      withoutEntities,\n      targetRange,\n    );\n\n    return insertFragmentIntoContentState(\n      withoutText,\n      withoutText.getSelectionAfter(),\n      fragment,\n      mergeBlockData,\n    );\n  },\n\n  removeRange(\n    contentState: ContentState,\n    rangeToRemove: SelectionState,\n    removalDirection: DraftRemovalDirection,\n  ): ContentState {\n    let startKey, endKey, startBlock, endBlock;\n    if (rangeToRemove.getIsBackward()) {\n      rangeToRemove = rangeToRemove.merge({\n        anchorKey: rangeToRemove.getFocusKey(),\n        anchorOffset: rangeToRemove.getFocusOffset(),\n        focusKey: rangeToRemove.getAnchorKey(),\n        focusOffset: rangeToRemove.getAnchorOffset(),\n        isBackward: false,\n      });\n    }\n    startKey = rangeToRemove.getAnchorKey();\n    endKey = rangeToRemove.getFocusKey();\n    startBlock = contentState.getBlockForKey(startKey);\n    endBlock = contentState.getBlockForKey(endKey);\n    const startOffset = rangeToRemove.getStartOffset();\n    const endOffset = rangeToRemove.getEndOffset();\n\n    const startEntityKey = startBlock.getEntityAt(startOffset);\n    const endEntityKey = endBlock.getEntityAt(endOffset - 1);\n\n    // Check whether the selection state overlaps with a single entity.\n    // If so, try to remove the appropriate substring of the entity text.\n    if (startKey === endKey) {\n      if (startEntityKey && startEntityKey === endEntityKey) {\n        const adjustedRemovalRange = getCharacterRemovalRange(\n          contentState.getEntityMap(),\n          startBlock,\n          endBlock,\n          rangeToRemove,\n          removalDirection,\n        );\n        return removeRangeFromContentState(contentState, adjustedRemovalRange);\n      }\n    }\n\n    const withoutEntities = removeEntitiesAtEdges(contentState, rangeToRemove);\n    return removeRangeFromContentState(withoutEntities, rangeToRemove);\n  },\n\n  splitBlock(\n    contentState: ContentState,\n    selectionState: SelectionState,\n  ): ContentState {\n    const withoutEntities = removeEntitiesAtEdges(contentState, selectionState);\n    const withoutText = removeRangeFromContentState(\n      withoutEntities,\n      selectionState,\n    );\n\n    return splitBlockInContentState(\n      withoutText,\n      withoutText.getSelectionAfter(),\n    );\n  },\n\n  applyInlineStyle(\n    contentState: ContentState,\n    selectionState: SelectionState,\n    inlineStyle: string,\n  ): ContentState {\n    return ContentStateInlineStyle.add(\n      contentState,\n      selectionState,\n      inlineStyle,\n    );\n  },\n\n  removeInlineStyle(\n    contentState: ContentState,\n    selectionState: SelectionState,\n    inlineStyle: string,\n  ): ContentState {\n    return ContentStateInlineStyle.remove(\n      contentState,\n      selectionState,\n      inlineStyle,\n    );\n  },\n\n  setBlockType(\n    contentState: ContentState,\n    selectionState: SelectionState,\n    blockType: DraftBlockType,\n  ): ContentState {\n    return modifyBlockForContentState(contentState, selectionState, block =>\n      block.merge({type: blockType, depth: 0}),\n    );\n  },\n\n  setBlockData(\n    contentState: ContentState,\n    selectionState: SelectionState,\n    blockData: Map<any, any>,\n  ): ContentState {\n    return modifyBlockForContentState(contentState, selectionState, block =>\n      block.merge({data: blockData}),\n    );\n  },\n\n  mergeBlockData(\n    contentState: ContentState,\n    selectionState: SelectionState,\n    blockData: Map<any, any>,\n  ): ContentState {\n    return modifyBlockForContentState(contentState, selectionState, block =>\n      block.merge({data: block.getData().merge(blockData)}),\n    );\n  },\n\n  applyEntity(\n    contentState: ContentState,\n    selectionState: SelectionState,\n    entityKey: ?string,\n  ): ContentState {\n    const withoutEntities = removeEntitiesAtEdges(contentState, selectionState);\n    return applyEntityToContentState(\n      withoutEntities,\n      selectionState,\n      entityKey,\n    );\n  },\n};\n\nmodule.exports = DraftModifier;\n"
  },
  {
    "path": "src/model/modifier/DraftRange.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nexport type DraftRange = {\n  start: number,\n  end: number,\n  ...\n};\n"
  },
  {
    "path": "src/model/modifier/DraftRemovableWord.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst TokenizeUtil = require('TokenizeUtil');\n\nconst punctuation = TokenizeUtil.getPunctuation();\n\n// The apostrophe and curly single quotes behave in a curious way: when\n// surrounded on both sides by word characters, they behave as word chars; when\n// either neighbor is punctuation or an end of the string, they behave as\n// punctuation.\nconst CHAMELEON_CHARS = \"['\\u2018\\u2019]\";\n\n// Remove the underscore, which should count as part of the removable word. The\n// \"chameleon chars\" also count as punctuation in this regex.\nconst WHITESPACE_AND_PUNCTUATION = '\\\\s|(?![_])' + punctuation;\n\nconst DELETE_STRING =\n  '^' +\n  '(?:' +\n  WHITESPACE_AND_PUNCTUATION +\n  ')*' +\n  '(?:' +\n  CHAMELEON_CHARS +\n  '|(?!' +\n  WHITESPACE_AND_PUNCTUATION +\n  ').)*' +\n  '(?:(?!' +\n  WHITESPACE_AND_PUNCTUATION +\n  ').)';\nconst DELETE_REGEX = new RegExp(DELETE_STRING);\n\nconst BACKSPACE_STRING =\n  '(?:(?!' +\n  WHITESPACE_AND_PUNCTUATION +\n  ').)' +\n  '(?:' +\n  CHAMELEON_CHARS +\n  '|(?!' +\n  WHITESPACE_AND_PUNCTUATION +\n  ').)*' +\n  '(?:' +\n  WHITESPACE_AND_PUNCTUATION +\n  ')*' +\n  '$';\nconst BACKSPACE_REGEX = new RegExp(BACKSPACE_STRING);\n\nfunction getRemovableWord(text: string, isBackward: boolean): string {\n  const matches = isBackward\n    ? BACKSPACE_REGEX.exec(text)\n    : DELETE_REGEX.exec(text);\n  return matches ? matches[0] : text;\n}\n\nconst DraftRemovableWord = {\n  getBackward(text: string): string {\n    return getRemovableWord(text, true);\n  },\n\n  getForward(text: string): string {\n    return getRemovableWord(text, false);\n  },\n};\n\nmodule.exports = DraftRemovableWord;\n"
  },
  {
    "path": "src/model/modifier/RichTextEditorUtil.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type ContentState from 'ContentState';\nimport type {DraftBlockType} from 'DraftBlockType';\nimport type {DraftEditorCommand} from 'DraftEditorCommand';\nimport type {DataObjectForLink, RichTextUtils} from 'RichTextUtils';\nimport type SelectionState from 'SelectionState';\nimport type URI from 'URI';\n\nconst DraftModifier = require('DraftModifier');\nconst EditorState = require('EditorState');\n\nconst adjustBlockDepthForContentState = require('adjustBlockDepthForContentState');\nconst nullthrows = require('nullthrows');\n\nconst RichTextEditorUtil: RichTextUtils = {\n  currentBlockContainsLink(editorState: EditorState): boolean {\n    const selection = editorState.getSelection();\n    const contentState = editorState.getCurrentContent();\n    return contentState\n      .getBlockForKey(selection.getAnchorKey())\n      .getCharacterList()\n      .slice(selection.getStartOffset(), selection.getEndOffset())\n      .some(v => {\n        const entity = v.getEntity();\n        return !!entity && contentState.getEntity(entity).getType() === 'LINK';\n      });\n  },\n\n  getCurrentBlockType(editorState: EditorState): DraftBlockType {\n    const selection = editorState.getSelection();\n    return editorState\n      .getCurrentContent()\n      .getBlockForKey(selection.getStartKey())\n      .getType();\n  },\n\n  getDataObjectForLinkURL(uri: URI): DataObjectForLink {\n    return {url: uri.toString()};\n  },\n\n  handleKeyCommand(\n    editorState: EditorState,\n    command: DraftEditorCommand | string,\n    eventTimeStamp: ?number,\n  ): ?EditorState {\n    switch (command) {\n      case 'bold':\n        return RichTextEditorUtil.toggleInlineStyle(editorState, 'BOLD');\n      case 'italic':\n        return RichTextEditorUtil.toggleInlineStyle(editorState, 'ITALIC');\n      case 'underline':\n        return RichTextEditorUtil.toggleInlineStyle(editorState, 'UNDERLINE');\n      case 'strikethrough':\n        return RichTextEditorUtil.toggleInlineStyle(\n          editorState,\n          'STRIKETHROUGH',\n        );\n      case 'code':\n        return RichTextEditorUtil.toggleCode(editorState);\n      case 'backspace':\n      case 'backspace-word':\n      case 'backspace-to-start-of-line':\n        return RichTextEditorUtil.onBackspace(editorState);\n      case 'delete':\n      case 'delete-word':\n      case 'delete-to-end-of-block':\n        return RichTextEditorUtil.onDelete(editorState);\n      default:\n        // they may have custom editor commands; ignore those\n        return null;\n    }\n  },\n\n  insertSoftNewline(editorState: EditorState): EditorState {\n    const contentState = DraftModifier.insertText(\n      editorState.getCurrentContent(),\n      editorState.getSelection(),\n      '\\n',\n      editorState.getCurrentInlineStyle(),\n      null,\n    );\n\n    const newEditorState = EditorState.push(\n      editorState,\n      contentState,\n      'insert-characters',\n    );\n\n    return EditorState.forceSelection(\n      newEditorState,\n      contentState.getSelectionAfter(),\n    );\n  },\n\n  /**\n   * For collapsed selections at the start of styled blocks, backspace should\n   * just remove the existing style.\n   */\n  onBackspace(editorState: EditorState): ?EditorState {\n    const selection = editorState.getSelection();\n    if (\n      !selection.isCollapsed() ||\n      selection.getAnchorOffset() ||\n      selection.getFocusOffset()\n    ) {\n      return null;\n    }\n\n    // First, try to remove a preceding atomic block.\n    const content = editorState.getCurrentContent();\n    const startKey = selection.getStartKey();\n    const blockBefore = content.getBlockBefore(startKey);\n\n    if (blockBefore && blockBefore.getType() === 'atomic') {\n      const blockMap = content.getBlockMap().delete(blockBefore.getKey());\n      const withoutAtomicBlock = content.merge({\n        blockMap,\n        selectionAfter: selection,\n      });\n      if (withoutAtomicBlock !== content) {\n        return EditorState.push(\n          editorState,\n          withoutAtomicBlock,\n          'remove-range',\n        );\n      }\n    }\n\n    // If that doesn't succeed, try to remove the current block style.\n    const withoutBlockStyle =\n      RichTextEditorUtil.tryToRemoveBlockStyle(editorState);\n\n    if (withoutBlockStyle) {\n      return EditorState.push(\n        editorState,\n        withoutBlockStyle,\n        'change-block-type',\n      );\n    }\n\n    return null;\n  },\n\n  onDelete(editorState: EditorState): ?EditorState {\n    const selection = editorState.getSelection();\n    if (!selection.isCollapsed()) {\n      return null;\n    }\n\n    const content = editorState.getCurrentContent();\n    const startKey = selection.getStartKey();\n    const block = content.getBlockForKey(startKey);\n    const length = block.getLength();\n\n    // The cursor is somewhere within the text. Behave normally.\n    if (selection.getStartOffset() < length) {\n      return null;\n    }\n\n    const blockAfter = content.getBlockAfter(startKey);\n\n    if (!blockAfter || blockAfter.getType() !== 'atomic') {\n      return null;\n    }\n\n    const atomicBlockTarget = selection.merge({\n      focusKey: blockAfter.getKey(),\n      focusOffset: blockAfter.getLength(),\n    });\n\n    const withoutAtomicBlock = DraftModifier.removeRange(\n      content,\n      atomicBlockTarget,\n      'forward',\n    );\n\n    if (withoutAtomicBlock !== content) {\n      return EditorState.push(editorState, withoutAtomicBlock, 'remove-range');\n    }\n\n    return null;\n  },\n\n  onTab(\n    event: SyntheticKeyboardEvent<>,\n    editorState: EditorState,\n  ): EditorState {\n    const selection = editorState.getSelection();\n    const key = selection.getAnchorKey();\n\n    const content = editorState.getCurrentContent();\n    const block = content.getBlockForKey(key);\n    const type = block.getType();\n    if (type !== 'unordered-list-item' && type !== 'ordered-list-item') {\n      return editorState;\n    }\n\n    event.preventDefault();\n\n    const withAdjustment = adjustBlockDepthForContentState(\n      content,\n      selection,\n      event.shiftKey ? -1 : 1,\n    );\n\n    return EditorState.push(editorState, withAdjustment, 'adjust-depth');\n  },\n\n  toggleBlockType(\n    editorState: EditorState,\n    blockType: DraftBlockType,\n  ): EditorState {\n    const selection = editorState.getSelection();\n    const startKey = selection.getStartKey();\n    let endKey = selection.getEndKey();\n    const content = editorState.getCurrentContent();\n    let target = selection;\n\n    // Triple-click can lead to a selection that includes offset 0 of the\n    // following block. The `SelectionState` for this case is accurate, but\n    // we should avoid toggling block type for the trailing block because it\n    // is a confusing interaction.\n    if (startKey !== endKey && selection.getEndOffset() === 0) {\n      const blockBefore = nullthrows(content.getBlockBefore(endKey));\n      endKey = blockBefore.getKey();\n      target = target.merge({\n        anchorKey: startKey,\n        anchorOffset: selection.getStartOffset(),\n        focusKey: endKey,\n        focusOffset: blockBefore.getLength(),\n        isBackward: false,\n      });\n    }\n\n    const hasAtomicBlock = content\n      .getBlockMap()\n      .skipWhile((_, k) => k !== startKey)\n      .reverse()\n      .skipWhile((_, k) => k !== endKey)\n      .some(v => v.getType() === 'atomic');\n\n    if (hasAtomicBlock) {\n      return editorState;\n    }\n\n    const typeToSet =\n      content.getBlockForKey(startKey).getType() === blockType\n        ? 'unstyled'\n        : blockType;\n\n    return EditorState.push(\n      editorState,\n      DraftModifier.setBlockType(content, target, typeToSet),\n      'change-block-type',\n    );\n  },\n\n  toggleCode(editorState: EditorState): EditorState {\n    const selection = editorState.getSelection();\n    const anchorKey = selection.getAnchorKey();\n    const focusKey = selection.getFocusKey();\n\n    if (selection.isCollapsed() || anchorKey !== focusKey) {\n      return RichTextEditorUtil.toggleBlockType(editorState, 'code-block');\n    }\n\n    return RichTextEditorUtil.toggleInlineStyle(editorState, 'CODE');\n  },\n\n  /**\n   * Toggle the specified inline style for the selection. If the\n   * user's selection is collapsed, apply or remove the style for the\n   * internal state. If it is not collapsed, apply the change directly\n   * to the document state.\n   */\n  toggleInlineStyle(\n    editorState: EditorState,\n    inlineStyle: string,\n  ): EditorState {\n    const selection = editorState.getSelection();\n    const currentStyle = editorState.getCurrentInlineStyle();\n\n    // If the selection is collapsed, toggle the specified style on or off and\n    // set the result as the new inline style override. This will then be\n    // used as the inline style for the next character to be inserted.\n    if (selection.isCollapsed()) {\n      return EditorState.setInlineStyleOverride(\n        editorState,\n        currentStyle.has(inlineStyle)\n          ? currentStyle.remove(inlineStyle)\n          : currentStyle.add(inlineStyle),\n      );\n    }\n\n    // If characters are selected, immediately apply or remove the\n    // inline style on the document state itself.\n    const content = editorState.getCurrentContent();\n    let newContent;\n\n    // If the style is already present for the selection range, remove it.\n    // Otherwise, apply it.\n    if (currentStyle.has(inlineStyle)) {\n      newContent = DraftModifier.removeInlineStyle(\n        content,\n        selection,\n        inlineStyle,\n      );\n    } else {\n      newContent = DraftModifier.applyInlineStyle(\n        content,\n        selection,\n        inlineStyle,\n      );\n    }\n\n    return EditorState.push(editorState, newContent, 'change-inline-style');\n  },\n\n  toggleLink(\n    editorState: EditorState,\n    targetSelection: SelectionState,\n    entityKey: ?string,\n  ): EditorState {\n    const withoutLink = DraftModifier.applyEntity(\n      editorState.getCurrentContent(),\n      targetSelection,\n      entityKey,\n    );\n\n    return EditorState.push(editorState, withoutLink, 'apply-entity');\n  },\n\n  /**\n   * When a collapsed cursor is at the start of a styled block, changes block\n   * type to 'unstyled'. Returns null if selection does not meet that criteria.\n   */\n  tryToRemoveBlockStyle(editorState: EditorState): ?ContentState {\n    const selection = editorState.getSelection();\n    const offset = selection.getAnchorOffset();\n    if (selection.isCollapsed() && offset === 0) {\n      const key = selection.getAnchorKey();\n      const content = editorState.getCurrentContent();\n      const block = content.getBlockForKey(key);\n\n      const type = block.getType();\n      const blockBefore = content.getBlockBefore(key);\n      if (\n        type === 'code-block' &&\n        blockBefore &&\n        blockBefore.getType() === 'code-block' &&\n        blockBefore.getLength() !== 0\n      ) {\n        return null;\n      }\n\n      if (type !== 'unstyled') {\n        return DraftModifier.setBlockType(content, selection, 'unstyled');\n      }\n    }\n    return null;\n  },\n};\n\nmodule.exports = RichTextEditorUtil;\n"
  },
  {
    "path": "src/model/modifier/RichTextUtils.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\nimport type ContentState from 'ContentState';\nimport type {DraftBlockType} from 'DraftBlockType';\nimport type {DraftEditorCommand} from 'DraftEditorCommand';\nimport type EditorState from 'EditorState';\nimport type SelectionState from 'SelectionState';\nimport type URI from 'URI';\n\nexport type DataObjectForLink = {url: string, ...};\n\nexport type RichTextUtils = {\n  currentBlockContainsLink: (editorState: EditorState) => boolean,\n  getCurrentBlockType: (editorState: EditorState) => DraftBlockType,\n  getDataObjectForLinkURL: (uri: URI) => DataObjectForLink,\n  handleKeyCommand: (\n    editorState: EditorState,\n    command: DraftEditorCommand | string,\n  ) => ?EditorState,\n  insertSoftNewline: (editorState: EditorState) => EditorState,\n  onBackspace: (editorState: EditorState) => ?EditorState,\n  onDelete: (editorState: EditorState) => ?EditorState,\n  onTab: (\n    event: SyntheticKeyboardEvent<>,\n    editorState: EditorState,\n  ) => EditorState,\n  toggleBlockType: (\n    editorState: EditorState,\n    blockType: DraftBlockType,\n  ) => EditorState,\n  toggleCode: (editorState: EditorState) => EditorState,\n  toggleInlineStyle: (\n    editorState: EditorState,\n    inlineStyle: string,\n  ) => EditorState,\n  toggleLink: (\n    editorState: EditorState,\n    targetSelection: SelectionState,\n    entityKey: ?string,\n  ) => EditorState,\n  tryToRemoveBlockStyle: (editorState: EditorState) => ?ContentState,\n  ...\n};\n"
  },
  {
    "path": "src/model/modifier/__tests__/AtomicBlockUtils-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\n\nconst AtomicBlockUtils = require('AtomicBlockUtils');\nconst BlockMapBuilder = require('BlockMapBuilder');\nconst ContentBlockNode = require('ContentBlockNode');\nconst EditorState = require('EditorState');\nconst SelectionState = require('SelectionState');\n\nconst getSampleStateForTesting = require('getSampleStateForTesting');\nconst invariant = require('invariant');\nconst mockUUID = require('mockUUID');\n\njest.mock('generateRandomKey');\n\njest.mock('uuid', () => mockUUID);\n\nconst sampleStateForTesting = getSampleStateForTesting();\nconst {editorState, selectionState} = sampleStateForTesting;\nlet {contentState} = sampleStateForTesting;\n\ncontentState = contentState.createEntity('TOKEN', 'MUTABLE');\nconst initialBlock = contentState.getBlockMap().first();\nconst ENTITY_KEY = contentState.getLastCreatedEntityKey();\nconst CHARACTER = ' ';\n\nconst getInvariantViolation = (msg: string) => {\n  try {\n    /* eslint-disable-next-line */\n    invariant(false, msg);\n  } catch (e) {\n    return e;\n  }\n};\n\nconst toggleExperimentalTreeDataSupport = (enabled: boolean) => {\n  jest.doMock('gkx', () => name => {\n    return name === 'draft_tree_data_support' ? enabled : false;\n  });\n};\n\nconst assertAtomic = (state: EditorState) => {\n  expect(\n    state.getCurrentContent().getBlockMap().toIndexedSeq().toJS(),\n  ).toMatchSnapshot();\n};\n\nconst assertInsertAtomicBlock = (\n  state: EditorState = editorState,\n  entity: string = ENTITY_KEY,\n  character: string = CHARACTER,\n  experimentalTreeDataSupport: boolean = false,\n) => {\n  toggleExperimentalTreeDataSupport(experimentalTreeDataSupport);\n  const newState = AtomicBlockUtils.insertAtomicBlock(state, entity, character);\n  assertAtomic(newState);\n  return newState;\n};\n\nconst assertMoveAtomicBlock = (\n  atomicBlock: BlockNodeRecord,\n  seletion: $FlowFixMe,\n  state: EditorState = editorState,\n  insertionType:\n    | void\n    | $TEMPORARY$string<'after'>\n    | $TEMPORARY$string<'before'>,\n) => {\n  const newState = AtomicBlockUtils.moveAtomicBlock(\n    state,\n    atomicBlock,\n    seletion,\n    insertionType,\n  );\n  assertAtomic(newState);\n  return newState;\n};\n\nbeforeEach(() => {\n  jest.resetModules();\n  jest.mock('uuid', () => mockUUID);\n});\n\ntest('must insert atomic at start of block with collapsed seletion', () => {\n  assertInsertAtomicBlock();\n});\n\ntest('must insert atomic within a block, via split with collapsed selection', () => {\n  assertInsertAtomicBlock(\n    EditorState.forceSelection(\n      editorState,\n      selectionState.merge({\n        anchorOffset: 2,\n        focusOffset: 2,\n      }),\n    ),\n  );\n});\n\ntest('must insert atomic after a block with collapsed selection', () => {\n  assertInsertAtomicBlock(\n    EditorState.forceSelection(\n      editorState,\n      selectionState.merge({\n        anchorOffset: initialBlock.getLength(),\n        focusOffset: initialBlock.getLength(),\n      }),\n    ),\n  );\n});\n\ntest('must move atomic at start of block with collapsed selection', () => {\n  // Insert atomic block at the first position\n  const resultEditor = assertInsertAtomicBlock();\n  const resultContent = resultEditor.getCurrentContent();\n  const firstBlock = resultContent.getBlockMap().first();\n  const atomicBlock = resultContent.getBlockMap().skip(1).first();\n\n  assertMoveAtomicBlock(\n    atomicBlock,\n    new SelectionState({\n      anchorKey: firstBlock.getKey(),\n      focusKey: firstBlock.getKey(),\n    }),\n    resultEditor,\n  );\n});\n\ntest('must move atomic at end of block with collapsed selection', () => {\n  // Insert atomic block at the first position\n  const resultEditor = assertInsertAtomicBlock();\n  const resultContent = resultEditor.getCurrentContent();\n  const lastBlock = resultContent.getBlockMap().last();\n  const atomicBlock = resultContent.getBlockMap().skip(1).first();\n\n  // Move atomic block at end of the last block\n  assertMoveAtomicBlock(\n    atomicBlock,\n    new SelectionState({\n      anchorKey: lastBlock.getKey(),\n      anchorOffset: lastBlock.getLength(),\n      focusKey: lastBlock.getKey(),\n      focusOffset: lastBlock.getLength(),\n    }),\n    resultEditor,\n  );\n});\n\ntest('must move atomic inbetween block with collapsed selection', () => {\n  // Insert atomic block at the first position\n  const resultEditor = assertInsertAtomicBlock();\n  const resultContent = resultEditor.getCurrentContent();\n  const atomicBlock = resultContent.getBlockMap().skip(1).first();\n  const thirdBlock = resultContent.getBlockMap().skip(2).first();\n\n  // Move atomic block inbetween the split parts of the third block\n  assertMoveAtomicBlock(\n    atomicBlock,\n    new SelectionState({\n      anchorKey: thirdBlock.getKey(),\n      anchorOffset: 2,\n      focusKey: thirdBlock.getKey(),\n      focusOffset: 2,\n    }),\n    resultEditor,\n  );\n});\n\ntest('must move atomic before block with collapsed selection', () => {\n  // Insert atomic block at the first position\n  const resultEditor = assertInsertAtomicBlock();\n  const resultContent = resultEditor.getCurrentContent();\n  const firstBlock = resultContent.getBlockMap().first();\n  const atomicBlock = resultContent.getBlockMap().skip(1).first();\n\n  // Move atomic block before the first block\n  assertMoveAtomicBlock(\n    atomicBlock,\n    new SelectionState({\n      anchorKey: firstBlock.getKey(),\n    }),\n    resultEditor,\n    'before',\n  );\n});\n\ntest('must move atomic after block with collapsed selection', () => {\n  // Insert atomic block at the first position\n  const resultEditor = assertInsertAtomicBlock();\n  const resultContent = resultEditor.getCurrentContent();\n  const atomicBlock = resultContent.getBlockMap().skip(1).first();\n  const lastBlock = resultContent.getBlockMap().last();\n\n  // Move atomic block after the last block\n  assertMoveAtomicBlock(\n    atomicBlock,\n    new SelectionState({\n      focusKey: lastBlock.getKey(),\n    }),\n    resultEditor,\n    'after',\n  );\n});\n\ntest(\"mustn't move atomic next to itself with collapsed selection\", () => {\n  // Insert atomic block at the second position\n  const resultEditor = assertInsertAtomicBlock(\n    EditorState.forceSelection(\n      editorState,\n      selectionState.merge({\n        anchorOffset: initialBlock.getLength(),\n        focusOffset: initialBlock.getLength(),\n      }),\n    ),\n  );\n  const resultContent = resultEditor.getCurrentContent();\n  const beforeAtomicBlock = resultContent.getBlockMap().first();\n  const atomicBlock = resultContent.getBlockMap().skip(1).first();\n  const afterAtomicBlock = resultContent.getBlockMap().skip(2).first();\n\n  // Move atomic block above itself by moving it after preceding block by\n  // replacement\n  expect(() => {\n    AtomicBlockUtils.moveAtomicBlock(\n      resultEditor,\n      atomicBlock,\n      new SelectionState({\n        anchorKey: beforeAtomicBlock.getKey(),\n        anchorOffset: beforeAtomicBlock.getLength(),\n        focusKey: beforeAtomicBlock.getKey(),\n        focusOffset: beforeAtomicBlock.getLength(),\n      }),\n    );\n  }).toThrow(getInvariantViolation('Block cannot be moved next to itself.'));\n\n  // Move atomic block above itself by moving it after preceding block\n  expect(() => {\n    AtomicBlockUtils.moveAtomicBlock(\n      resultEditor,\n      atomicBlock,\n      new SelectionState({\n        anchorKey: beforeAtomicBlock.getKey(),\n        focusKey: beforeAtomicBlock.getKey(),\n      }),\n      'after',\n    );\n  }).toThrow(getInvariantViolation('Block cannot be moved next to itself.'));\n\n  // Move atomic block above itself by replacement\n  expect(() => {\n    AtomicBlockUtils.moveAtomicBlock(\n      resultEditor,\n      atomicBlock,\n      new SelectionState({\n        anchorKey: atomicBlock.getKey(),\n        focusKey: atomicBlock.getKey(),\n        anchorOffset: atomicBlock.getLength(),\n        focusOffset: atomicBlock.getLength(),\n      }),\n    );\n  }).toThrow(getInvariantViolation('Block cannot be moved next to itself.'));\n\n  // Move atomic block above itself\n  expect(() => {\n    AtomicBlockUtils.moveAtomicBlock(\n      resultEditor,\n      atomicBlock,\n      new SelectionState({\n        anchorKey: atomicBlock.getKey(),\n      }),\n      'before',\n    );\n  }).toThrow(getInvariantViolation('Block cannot be moved next to itself.'));\n\n  // Move atomic block below itself by moving it before following block by replacement\n  expect(() => {\n    AtomicBlockUtils.moveAtomicBlock(\n      resultEditor,\n      atomicBlock,\n      new SelectionState({\n        anchorKey: afterAtomicBlock.getKey(),\n        focusKey: afterAtomicBlock.getKey(),\n      }),\n    );\n  }).toThrow(getInvariantViolation('Block cannot be moved next to itself.'));\n\n  // Move atomic block below itself by moving it before following block\n  expect(() => {\n    AtomicBlockUtils.moveAtomicBlock(\n      resultEditor,\n      atomicBlock,\n      new SelectionState({\n        anchorKey: afterAtomicBlock.getKey(),\n        focusKey: afterAtomicBlock.getKey(),\n      }),\n      'before',\n    );\n  }).toThrow(getInvariantViolation('Block cannot be moved next to itself.'));\n\n  // Move atomic block below itself by replacement\n  expect(() => {\n    AtomicBlockUtils.moveAtomicBlock(\n      resultEditor,\n      atomicBlock,\n      new SelectionState({\n        anchorKey: atomicBlock.getKey(),\n        anchorOffset: atomicBlock.getLength(),\n        focusKey: atomicBlock.getKey(),\n        focusOffset: atomicBlock.getLength(),\n      }),\n    );\n  }).toThrow(getInvariantViolation('Block cannot be moved next to itself.'));\n\n  // Move atomic block below itself\n  expect(() => {\n    AtomicBlockUtils.moveAtomicBlock(\n      resultEditor,\n      atomicBlock,\n      new SelectionState({\n        focusKey: atomicBlock.getKey(),\n      }),\n      'after',\n    );\n  }).toThrow(getInvariantViolation('Block cannot be moved next to itself.'));\n});\n\n/**\n * Non collapsed\n */\ntest('must insert atomic at start of block', () => {\n  assertInsertAtomicBlock(\n    EditorState.forceSelection(\n      editorState,\n      selectionState.merge({\n        anchorOffset: 0,\n        focusOffset: 2,\n      }),\n    ),\n  );\n});\n\ntest('must insert atomic within a block', () => {\n  assertInsertAtomicBlock(\n    EditorState.forceSelection(\n      editorState,\n      selectionState.merge({\n        anchorOffset: 1,\n        focusOffset: 2,\n      }),\n    ),\n  );\n});\n\ntest('must insert atomic at end of block', () => {\n  const origLength = initialBlock.getLength();\n  assertInsertAtomicBlock(\n    EditorState.forceSelection(\n      editorState,\n      selectionState.merge({\n        anchorOffset: origLength - 2,\n        focusOffset: origLength,\n      }),\n    ),\n  );\n});\n\ntest('must insert atomic for cross-block selection', () => {\n  const originalThirdBlock = contentState.getBlockMap().skip(2).first();\n  assertInsertAtomicBlock(\n    EditorState.forceSelection(\n      editorState,\n      selectionState.merge({\n        anchorOffset: 2,\n        focusKey: originalThirdBlock.getKey(),\n        focusOffset: 2,\n      }),\n    ),\n  );\n});\n\ntest('must move atomic at start of block', () => {\n  // Insert atomic block at the first position\n  const resultEditor = assertInsertAtomicBlock();\n  const resultContent = resultEditor.getCurrentContent();\n  const atomicBlock = resultContent.getBlockMap().skip(1).first();\n  const lastBlock = resultContent.getBlockMap().last();\n\n  // Move atomic block at start of the last block\n  assertMoveAtomicBlock(\n    atomicBlock,\n    new SelectionState({\n      anchorKey: lastBlock.getKey(),\n      anchorOffset: 0,\n      focusKey: lastBlock.getKey(),\n      focusOffset: 2,\n    }),\n    resultEditor,\n  );\n});\n\ntest('must move atomic at end of block', () => {\n  // Insert atomic block at the first position\n  const resultEditor = assertInsertAtomicBlock();\n  const resultContent = resultEditor.getCurrentContent();\n  const atomicBlock = resultContent.getBlockMap().skip(1).first();\n  const lastBlock = resultContent.getBlockMap().last();\n\n  // Move atomic block at end of the last block\n  assertMoveAtomicBlock(\n    atomicBlock,\n    new SelectionState({\n      anchorKey: lastBlock.getKey(),\n      anchorOffset: lastBlock.getLength() - 2,\n      focusKey: lastBlock.getKey(),\n      focusOffset: lastBlock.getLength(),\n    }),\n    resultEditor,\n  );\n});\n\ntest('must move atomic inbetween block', () => {\n  // Insert atomic block at the first position\n  const resultEditor = assertInsertAtomicBlock();\n  const resultContent = resultEditor.getCurrentContent();\n  const atomicBlock = resultContent.getBlockMap().skip(1).first();\n  const thirdBlock = resultContent.getBlockMap().skip(2).first();\n\n  // Move atomic block inbetween the split parts of the third block\n  assertMoveAtomicBlock(\n    atomicBlock,\n    new SelectionState({\n      anchorKey: thirdBlock.getKey(),\n      anchorOffset: 1,\n      focusKey: thirdBlock.getKey(),\n      focusOffset: 2,\n    }),\n    resultEditor,\n  );\n});\n\ntest('must move atomic before block', () => {\n  // Insert atomic block at the first position\n  const resultEditor = assertInsertAtomicBlock();\n  const resultContent = resultEditor.getCurrentContent();\n  const firstBlock = resultContent.getBlockMap().first();\n  const atomicBlock = resultContent.getBlockMap().skip(1).first();\n  const lastBlock = resultContent.getBlockMap().last();\n\n  // Move atomic block before the first block\n  assertMoveAtomicBlock(\n    atomicBlock,\n    new SelectionState({\n      anchorKey: firstBlock.getKey(),\n      anchorOffset: 2,\n      focusKey: lastBlock.getKey(),\n      focusOffset: 2,\n    }),\n    resultEditor,\n    'before',\n  );\n});\n\ntest('must move atomic after block', () => {\n  // Insert atomic block at the first position\n  const resultEditor = assertInsertAtomicBlock();\n  const resultContent = resultEditor.getCurrentContent();\n  const firstBlock = resultContent.getBlockMap().first();\n  const atomicBlock = resultContent.getBlockMap().skip(1).first();\n  const lastBlock = resultContent.getBlockMap().last();\n\n  // Move atomic block after the last block\n  assertMoveAtomicBlock(\n    atomicBlock,\n    new SelectionState({\n      anchorKey: firstBlock.getKey(),\n      anchorOffset: 2,\n      focusKey: lastBlock.getKey(),\n      focusOffset: 2,\n    }),\n    resultEditor,\n    'after',\n  );\n});\n\ntest(\"mustn't move atomic next to itself\", () => {\n  // Insert atomic block at the second position\n  const resultEditor = assertInsertAtomicBlock(\n    EditorState.forceSelection(\n      editorState,\n      selectionState.merge({\n        anchorOffset: initialBlock.getLength(),\n        focusOffset: initialBlock.getLength(),\n      }),\n    ),\n  );\n  const resultContent = resultEditor.getCurrentContent();\n  const beforeAtomicBlock = resultContent.getBlockMap().first();\n  const atomicBlock = resultContent.getBlockMap().skip(1).first();\n  const afterAtomicBlock = resultContent.getBlockMap().skip(2).first();\n\n  // Move atomic block above itself by moving it after preceding block by\n  // replacement\n  expect(() => {\n    AtomicBlockUtils.moveAtomicBlock(\n      resultEditor,\n      atomicBlock,\n      new SelectionState({\n        anchorKey: beforeAtomicBlock.getKey(),\n        anchorOffset: beforeAtomicBlock.getLength() - 2,\n        focusKey: beforeAtomicBlock.getKey(),\n        focusOffset: beforeAtomicBlock.getLength(),\n      }),\n    );\n  }).toThrow(getInvariantViolation('Block cannot be moved next to itself.'));\n\n  // Move atomic block below itself by moving it before following block by\n  // replacement\n  expect(() => {\n    AtomicBlockUtils.moveAtomicBlock(\n      resultEditor,\n      atomicBlock,\n      new SelectionState({\n        anchorKey: afterAtomicBlock.getKey(),\n        anchorOffset: 0,\n        focusKey: afterAtomicBlock.getKey(),\n        focusOffset: 2,\n      }),\n    );\n  }).toThrow(getInvariantViolation('Block cannot be moved next to itself.'));\n});\n\ntest('must be able to insert atomic block when experimentalTreeDataSupport is enabled', () => {\n  // Insert atomic block at the first position\n  assertInsertAtomicBlock(\n    EditorState.forceSelection(\n      EditorState.createWithContent(\n        contentState.setBlockMap(\n          BlockMapBuilder.createFromArray([\n            new ContentBlockNode({\n              text: 'first block',\n              key: 'A',\n            }),\n          ]),\n        ),\n      ),\n      SelectionState.createEmpty('A'),\n    ),\n    ENTITY_KEY,\n    CHARACTER,\n    true,\n  );\n});\n\ntest('must be able to move atomic block when experimentalTreeDataSupport is enabled', () => {\n  // Insert atomic block at the first position\n  const resultEditor = assertInsertAtomicBlock(\n    EditorState.forceSelection(\n      EditorState.createWithContent(\n        contentState.setBlockMap(\n          BlockMapBuilder.createFromArray([\n            new ContentBlockNode({\n              text: 'first block',\n              key: 'A',\n            }),\n          ]),\n        ),\n      ),\n      SelectionState.createEmpty('A'),\n    ),\n    ENTITY_KEY,\n    CHARACTER,\n    true,\n  );\n\n  const resultContent = resultEditor.getCurrentContent();\n  const lastBlock = resultContent.getBlockMap().last();\n  const atomicBlock = resultContent.getBlockMap().skip(1).first();\n\n  // Move atomic block at end of the last block\n  assertMoveAtomicBlock(\n    atomicBlock,\n    new SelectionState({\n      anchorKey: lastBlock.getKey(),\n      anchorOffset: lastBlock.getLength(),\n      focusKey: lastBlock.getKey(),\n      focusOffset: lastBlock.getLength(),\n      isBackward: false,\n      hasFocus: false,\n    }),\n    resultEditor,\n    'after',\n  );\n});\n"
  },
  {
    "path": "src/model/modifier/__tests__/DraftRemovableWord-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nexpect.addSnapshotSerializer(require('NonASCIIStringSnapshotSerializer'));\n\nconst DraftRemovableWord = require('DraftRemovableWord');\n\nlet forward;\nlet backward;\n\nconst accents = 'th\\u00e9 f\\u00e0bregas';\nconst arabic = '\\u0637\\u0638\\u0639 \\u063A\\u063B\\u063C';\nconst cyrillic = '\\u0430\\u0448\\u043e\\u043a \\u0431\\u0414\\u0416\\u0426';\nconst english = 'the animals';\nconst halfWidthHangul = '\\uffa3\\uffa6\\uffb0 \\uffa1\\uffa2\\uffb2';\nconst japanese = '\\u4f1a\\u8b70\\u4e2d \\u30cf\\u30c3\\u30b7\\u30e5';\nconst korean = '\\ud2b8\\uc704\\ud130 \\ud2b8\\uc704\\ud130';\nconst withNumbers = 'f14 tomcat';\n\nbeforeEach(() => {\n  jest.resetModules();\n  forward = DraftRemovableWord.getForward;\n  backward = DraftRemovableWord.getBackward;\n});\n\ntest('must identify words looking forward', () => {\n  expect(forward(english)).toMatchSnapshot();\n  expect(forward(accents)).toMatchSnapshot();\n  expect(forward(arabic)).toMatchSnapshot();\n  expect(forward(japanese)).toMatchSnapshot();\n  expect(forward(korean)).toMatchSnapshot();\n  expect(forward(halfWidthHangul)).toMatchSnapshot();\n  expect(forward(cyrillic)).toMatchSnapshot();\n  expect(forward(withNumbers)).toMatchSnapshot();\n});\n\ntest('must identify words with apostrophes looking forward', () => {\n  expect(forward(\"you're correct.\")).toMatchSnapshot();\n});\n\ntest('must identify words with curly quotes looking forward', () => {\n  expect(forward('you\\u2019re correct.')).toMatchSnapshot();\n});\n\ntest('must identify punctuation with apostrophes', () => {\n  expect(forward(\"'hello'\")).toMatchSnapshot();\n  expect(backward(\"'hello'\")).toMatchSnapshot();\n  expect(forward('\\u2018hello\\u2019')).toMatchSnapshot();\n  expect(backward('\\u2018hello\\u2019')).toMatchSnapshot();\n\n  expect(forward(\"('hello')\")).toMatchSnapshot();\n  expect(backward(\"('hello')\")).toMatchSnapshot();\n  expect(forward(\".'.\")).toMatchSnapshot();\n  expect(backward(\".'.\")).toMatchSnapshot();\n});\n\ntest('must identify words with underscores', () => {\n  expect(forward('under_score hey')).toMatchSnapshot();\n  expect(backward('hey under_score')).toMatchSnapshot();\n});\n\ntest('must identify words led by spaces looking forward', () => {\n  expect(forward('  ' + english)).toMatchSnapshot();\n  expect(forward('    ' + accents)).toMatchSnapshot();\n  expect(forward('      ' + arabic)).toMatchSnapshot();\n});\n\ntest('must identify words led by punctuation looking forward', () => {\n  expect(forward('.' + english)).toMatchSnapshot();\n  expect(forward('|' + english)).toMatchSnapshot();\n  expect(forward('^' + english)).toMatchSnapshot();\n  expect(forward('\\u060d\\uFD3e\\uFD3F' + english)).toMatchSnapshot();\n  expect(forward('.. .. ..' + english)).toMatchSnapshot();\n});\n\ntest('must identify punct/whitespace strings looking forward', () => {\n  expect(forward('    ')).toMatchSnapshot();\n  expect(forward('\\u060d\\uFD3e\\uFD3F')).toMatchSnapshot();\n  expect(forward('. . . . .')).toMatchSnapshot();\n  expect(forward('   !!!???   ')).toMatchSnapshot();\n});\n\ntest('must identify words looking backward', () => {\n  expect(backward(english)).toMatchSnapshot();\n  expect(backward(accents)).toMatchSnapshot();\n  expect(backward(arabic)).toMatchSnapshot();\n  expect(backward(japanese)).toMatchSnapshot();\n  expect(backward(korean)).toMatchSnapshot();\n  expect(backward(halfWidthHangul)).toMatchSnapshot();\n  expect(backward(cyrillic)).toMatchSnapshot();\n  expect(backward(withNumbers)).toMatchSnapshot();\n});\n\ntest('must identify words with apostrophes looking backward', () => {\n  expect(backward(\"you don't\")).toMatchSnapshot();\n});\n\ntest('must identify words ended by spaces looking backward', () => {\n  expect(backward(english + '  ')).toMatchSnapshot();\n  expect(backward(accents + '    ')).toMatchSnapshot();\n  expect(backward(arabic + '      ')).toMatchSnapshot();\n});\n\ntest('must identify words ended by punctuation looking backward', () => {\n  expect(backward(english + '.')).toMatchSnapshot();\n  expect(backward(english + '|')).toMatchSnapshot();\n  expect(backward(english + '^')).toMatchSnapshot();\n  expect(backward(english + '\\u060d\\uFD3e\\uFD3F')).toMatchSnapshot();\n  expect(backward(english + '.. .. ..')).toMatchSnapshot();\n});\n\ntest('must identify punct/whitespace strings looking backward', () => {\n  expect(backward('    ')).toMatchSnapshot();\n  expect(backward('\\u060d\\uFD3e\\uFD3F')).toMatchSnapshot();\n  expect(backward('. . . . .')).toMatchSnapshot();\n  expect(backward('   !!!???   ')).toMatchSnapshot();\n});\n\ntest('must identify nothing in an empty string', () => {\n  expect(forward('')).toMatchSnapshot();\n  expect(backward('')).toMatchSnapshot();\n});\n"
  },
  {
    "path": "src/model/modifier/__tests__/RichTextEditorUtil-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @format\n * @oncall draft_js\n */\n\nconst AtomicBlockUtils = require('AtomicBlockUtils');\nconst DraftModifier = require('DraftModifier');\nconst EditorState = require('EditorState');\nconst RichTextEditorUtil = require('RichTextEditorUtil');\nconst SelectionState = require('SelectionState');\n\nconst getSampleStateForTesting = require('getSampleStateForTesting');\n\nconst {editorState, selectionState} = getSampleStateForTesting();\nconst {onBackspace, onDelete, onTab, tryToRemoveBlockStyle} =\n  RichTextEditorUtil;\n\nconst insertAtomicBlock = targetEditorState => {\n  const entityKey = targetEditorState\n    .getCurrentContent()\n    .createEntity('TEST', 'IMMUTABLE', null)\n    .getLastCreatedEntityKey();\n  const character = ' ';\n  const movedSelection = EditorState.moveSelectionToEnd(targetEditorState);\n  return AtomicBlockUtils.insertAtomicBlock(\n    movedSelection,\n    entityKey,\n    character,\n  );\n};\n\ntest('onBackspace does not handle non-zero-offset or non-collapsed selections', () => {\n  const nonZero = selectionState.merge({anchorOffset: 2, focusOffset: 2});\n  expect(\n    onBackspace(EditorState.forceSelection(editorState, nonZero)),\n  ).toMatchSnapshot();\n\n  const nonCollapsed = nonZero.merge({anchorOffset: 0});\n  expect(\n    onBackspace(EditorState.forceSelection(editorState, nonCollapsed)),\n  ).toMatchSnapshot();\n});\n\ntest('onBackspace resets the current block type if empty', () => {\n  const contentState = editorState.getCurrentContent();\n  const lastBlock = contentState.getLastBlock();\n  const lastBlockKey = lastBlock.getKey();\n\n  // Remove the current text from the blockquote.\n  const resetBlockquote = DraftModifier.removeRange(\n    contentState,\n    new SelectionState({\n      anchorKey: lastBlockKey,\n      anchorOffset: 0,\n      focusKey: lastBlockKey,\n      focusOffset: lastBlock.getLength(),\n    }),\n    'backward',\n  );\n\n  const withEmptyBlockquote = EditorState.push(\n    editorState,\n    resetBlockquote,\n    'remove-range',\n  );\n\n  const afterBackspace = onBackspace(withEmptyBlockquote);\n  const lastBlockNow = afterBackspace.getCurrentContent().getLastBlock();\n\n  expect(lastBlockNow.toJS()).toMatchSnapshot();\n});\n\ntest('onBackspace resets the current block type at the start of the first block', () => {\n  const contentState = editorState.getCurrentContent();\n\n  const setListItem = DraftModifier.setBlockType(\n    contentState,\n    selectionState,\n    'unordered-list-item',\n  );\n\n  const withListItem = EditorState.push(\n    editorState,\n    setListItem,\n    'change-block-type',\n  );\n\n  const afterBackspace = onBackspace(withListItem);\n  const firstBlockNow = afterBackspace.getCurrentContent().getFirstBlock();\n\n  expect(firstBlockNow.toJS()).toMatchSnapshot();\n});\n\ntest('onBackspace removes a preceding atomic block', () => {\n  const blockSizeBeforeRemove = editorState\n    .getCurrentContent()\n    .getBlockMap().size;\n  const withAtomicBlock = insertAtomicBlock(editorState);\n  const afterBackspace = onBackspace(withAtomicBlock);\n  const contentState = afterBackspace.getCurrentContent();\n  const blockMap = contentState.getBlockMap();\n  expect(blockMap.size === blockSizeBeforeRemove + 1).toMatchSnapshot();\n  expect(\n    blockMap.some(block => block.getType() === 'atomic'),\n  ).toMatchSnapshot();\n});\n\ntest('onDelete does not handle non-block-end or non-collapsed selections', () => {\n  const nonZero = selectionState.merge({anchorOffset: 2, focusOffset: 2});\n  expect(\n    onDelete(EditorState.forceSelection(editorState, nonZero)) === null,\n  ).toMatchSnapshot();\n\n  const nonCollapsed = nonZero.merge({anchorOffset: 0});\n  expect(\n    onDelete(EditorState.forceSelection(editorState, nonCollapsed)) === null,\n  ).toMatchSnapshot();\n});\n\ntest('onDelete removes a following atomic block', () => {\n  const blockSizeBeforeRemove = editorState\n    .getCurrentContent()\n    .getBlockMap().size;\n  const withAtomicBlock = insertAtomicBlock(editorState);\n  const content = withAtomicBlock.getCurrentContent();\n  const atomicKey = content\n    .getBlockMap()\n    .find(block => block.getType() === 'atomic')\n    .getKey();\n\n  const blockBefore = content.getBlockBefore(atomicKey);\n  const keyBefore = blockBefore.getKey();\n  const lengthBefore = blockBefore.getLength();\n\n  const withSelectionAboveAtomic = EditorState.forceSelection(\n    withAtomicBlock,\n    new SelectionState({\n      anchorKey: keyBefore,\n      anchorOffset: lengthBefore,\n      focusKey: keyBefore,\n      focusOffset: lengthBefore,\n    }),\n  );\n\n  const afterDelete = onDelete(withSelectionAboveAtomic);\n  const blockMapAfterDelete = afterDelete.getCurrentContent().getBlockMap();\n\n  expect(\n    blockMapAfterDelete.some(block => block.getType() === 'atomic'),\n  ).toMatchSnapshot();\n\n  expect(\n    blockMapAfterDelete.size === blockSizeBeforeRemove + 1,\n  ).toMatchSnapshot();\n});\n\ntest('tryToRemoveBlockStyleonDelete breaks out of code block on enter two blank lines', () => {\n  const blankLine = selectionState.merge({anchorKey: 'e', focusKey: 'e'});\n  const withBlankLine = EditorState.forceSelection(editorState, blankLine);\n\n  const afterEnter = tryToRemoveBlockStyle(withBlankLine);\n  const lastBlock = afterEnter.getLastBlock();\n\n  expect(lastBlock.toJS()).toMatchSnapshot();\n});\n\ndescribe('onTab on list block', () => {\n  const setListBlock = (contentState, type) =>\n    DraftModifier.setBlockType(contentState, selectionState, type);\n  const changeBlockType = setListItem =>\n    EditorState.push(editorState, setListItem, 'change-block-type');\n  const getFirstBlockDepth = contentState =>\n    contentState.getCurrentContent().getFirstBlock().getDepth();\n  const addTab = contentState =>\n    onTab({preventDefault: () => {}}, contentState);\n\n  test('increases the depth of unordered-list-item', () => {\n    const contentState = editorState.getCurrentContent();\n    const setListItem = setListBlock(contentState, 'unordered-list-item');\n    const withListItem = changeBlockType(setListItem);\n\n    const afterFirstTab = addTab(withListItem);\n    const depthAfterFirstTab = getFirstBlockDepth(afterFirstTab);\n\n    expect(depthAfterFirstTab).toBe(1);\n\n    const afterSecondTab = addTab(afterFirstTab);\n    const depthAfterSecondTab = getFirstBlockDepth(afterSecondTab);\n\n    expect(depthAfterSecondTab).toBe(2);\n  });\n\n  test('increases the depth of unordered-list-item', () => {\n    const contentState = editorState.getCurrentContent();\n    const setListItem = setListBlock(contentState, 'ordered-list-item');\n    const withListItem = changeBlockType(setListItem);\n\n    const afterFirstTab = addTab(withListItem);\n    const depthAfterFirstTab = getFirstBlockDepth(afterFirstTab);\n\n    expect(depthAfterFirstTab).toBe(1);\n\n    const afterSecondTab = addTab(afterFirstTab);\n    const depthAfterSecondTab = getFirstBlockDepth(afterSecondTab);\n\n    expect(depthAfterSecondTab).toBe(2);\n  });\n});\n"
  },
  {
    "path": "src/model/modifier/__tests__/__snapshots__/AtomicBlockUtils-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must be able to insert atomic block when experimentalTreeDataSupport is enabled 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"key0\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"nextSibling\": \"key4\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key0\",\n    \"text\": \"first block\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must be able to move atomic block when experimentalTreeDataSupport is enabled 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"key0\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"nextSibling\": \"key4\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key0\",\n    \"text\": \"first block\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must be able to move atomic block when experimentalTreeDataSupport is enabled 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"key4\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"nextSibling\": \"key0\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"first block\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key4\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n]\n`;\n\nexports[`must insert atomic after a block with collapsed selection 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must insert atomic at end of block 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alp\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must insert atomic at start of block 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"pha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must insert atomic at start of block with collapsed seletion 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must insert atomic for cross-block selection 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Al\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"st\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must insert atomic within a block 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"A\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"pha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must insert atomic within a block, via split with collapsed selection 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Al\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"pha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must move atomic after block 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must move atomic after block 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n]\n`;\n\nexports[`must move atomic after block with collapsed selection 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must move atomic after block with collapsed selection 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n]\n`;\n\nexports[`must move atomic at end of block 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must move atomic at end of block 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charl\",\n    \"type\": \"blockquote\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n]\n`;\n\nexports[`must move atomic at end of block with collapsed selection 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must move atomic at end of block with collapsed selection 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n]\n`;\n\nexports[`must move atomic at start of block 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must move atomic at start of block 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"arlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must move atomic at start of block with collapsed selection 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must move atomic at start of block with collapsed selection 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must move atomic before block 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must move atomic before block 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must move atomic before block with collapsed selection 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must move atomic before block with collapsed selection 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must move atomic inbetween block 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must move atomic inbetween block 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"A\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key5\",\n    \"text\": \"pha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must move atomic inbetween block with collapsed selection 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must move atomic inbetween block with collapsed selection 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"Al\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key5\",\n    \"text\": \"pha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`mustn't move atomic next to itself 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`mustn't move atomic next to itself with collapsed selection 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"3\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n"
  },
  {
    "path": "src/model/modifier/__tests__/__snapshots__/DraftRemovableWord-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must identify nothing in an empty string 1`] = `\"\"`;\n\nexports[`must identify nothing in an empty string 2`] = `\"\"`;\n\nexports[`must identify punct/whitespace strings looking backward 1`] = `\"    \"`;\n\nexports[`must identify punct/whitespace strings looking backward 2`] = `\"\\\\u060d\\\\ufd3e\\\\ufd3f\"`;\n\nexports[`must identify punct/whitespace strings looking backward 3`] = `\". . . . .\"`;\n\nexports[`must identify punct/whitespace strings looking backward 4`] = `\"   !!!???   \"`;\n\nexports[`must identify punct/whitespace strings looking forward 1`] = `\"    \"`;\n\nexports[`must identify punct/whitespace strings looking forward 2`] = `\"\\\\u060d\\\\ufd3e\\\\ufd3f\"`;\n\nexports[`must identify punct/whitespace strings looking forward 3`] = `\". . . . .\"`;\n\nexports[`must identify punct/whitespace strings looking forward 4`] = `\"   !!!???   \"`;\n\nexports[`must identify punctuation with apostrophes 1`] = `\"'hello\"`;\n\nexports[`must identify punctuation with apostrophes 2`] = `\"hello'\"`;\n\nexports[`must identify punctuation with apostrophes 3`] = `\"\\\\u2018hello\"`;\n\nexports[`must identify punctuation with apostrophes 4`] = `\"hello\\\\u2019\"`;\n\nexports[`must identify punctuation with apostrophes 5`] = `\"('hello\"`;\n\nexports[`must identify punctuation with apostrophes 6`] = `\"hello')\"`;\n\nexports[`must identify punctuation with apostrophes 7`] = `\".'.\"`;\n\nexports[`must identify punctuation with apostrophes 8`] = `\".'.\"`;\n\nexports[`must identify words ended by punctuation looking backward 1`] = `\"animals.\"`;\n\nexports[`must identify words ended by punctuation looking backward 2`] = `\"animals|\"`;\n\nexports[`must identify words ended by punctuation looking backward 3`] = `\"animals^\"`;\n\nexports[`must identify words ended by punctuation looking backward 4`] = `\"animals\\\\u060d\\\\ufd3e\\\\ufd3f\"`;\n\nexports[`must identify words ended by punctuation looking backward 5`] = `\"animals.. .. ..\"`;\n\nexports[`must identify words ended by spaces looking backward 1`] = `\"animals  \"`;\n\nexports[`must identify words ended by spaces looking backward 2`] = `\"f\\\\u00e0bregas    \"`;\n\nexports[`must identify words ended by spaces looking backward 3`] = `\"\\\\u063a\\\\u063b\\\\u063c      \"`;\n\nexports[`must identify words led by punctuation looking forward 1`] = `\".the\"`;\n\nexports[`must identify words led by punctuation looking forward 2`] = `\"|the\"`;\n\nexports[`must identify words led by punctuation looking forward 3`] = `\"^the\"`;\n\nexports[`must identify words led by punctuation looking forward 4`] = `\"\\\\u060d\\\\ufd3e\\\\ufd3fthe\"`;\n\nexports[`must identify words led by punctuation looking forward 5`] = `\".. .. ..the\"`;\n\nexports[`must identify words led by spaces looking forward 1`] = `\"  the\"`;\n\nexports[`must identify words led by spaces looking forward 2`] = `\"    th\\\\u00e9\"`;\n\nexports[`must identify words led by spaces looking forward 3`] = `\"      \\\\u0637\\\\u0638\\\\u0639\"`;\n\nexports[`must identify words looking backward 1`] = `\"animals\"`;\n\nexports[`must identify words looking backward 2`] = `\"f\\\\u00e0bregas\"`;\n\nexports[`must identify words looking backward 3`] = `\"\\\\u063a\\\\u063b\\\\u063c\"`;\n\nexports[`must identify words looking backward 4`] = `\"\\\\u30cf\\\\u30c3\\\\u30b7\\\\u30e5\"`;\n\nexports[`must identify words looking backward 5`] = `\"\\\\ud2b8\\\\uc704\\\\ud130\"`;\n\nexports[`must identify words looking backward 6`] = `\"\\\\uffa1\\\\uffa2\\\\uffb2\"`;\n\nexports[`must identify words looking backward 7`] = `\"\\\\u0431\\\\u0414\\\\u0416\\\\u0426\"`;\n\nexports[`must identify words looking backward 8`] = `\"tomcat\"`;\n\nexports[`must identify words looking forward 1`] = `\"the\"`;\n\nexports[`must identify words looking forward 2`] = `\"th\\\\u00e9\"`;\n\nexports[`must identify words looking forward 3`] = `\"\\\\u0637\\\\u0638\\\\u0639\"`;\n\nexports[`must identify words looking forward 4`] = `\"\\\\u4f1a\\\\u8b70\\\\u4e2d\"`;\n\nexports[`must identify words looking forward 5`] = `\"\\\\ud2b8\\\\uc704\\\\ud130\"`;\n\nexports[`must identify words looking forward 6`] = `\"\\\\uffa3\\\\uffa6\\\\uffb0\"`;\n\nexports[`must identify words looking forward 7`] = `\"\\\\u0430\\\\u0448\\\\u043e\\\\u043a\"`;\n\nexports[`must identify words looking forward 8`] = `\"f14\"`;\n\nexports[`must identify words with apostrophes looking backward 1`] = `\"don't\"`;\n\nexports[`must identify words with apostrophes looking forward 1`] = `\"you're\"`;\n\nexports[`must identify words with curly quotes looking forward 1`] = `\"you\\\\u2019re\"`;\n\nexports[`must identify words with underscores 1`] = `\"under_score\"`;\n\nexports[`must identify words with underscores 2`] = `\"under_score\"`;\n"
  },
  {
    "path": "src/model/modifier/__tests__/__snapshots__/RichTextEditorUtil-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`onBackspace does not handle non-zero-offset or non-collapsed selections 1`] = `null`;\n\nexports[`onBackspace does not handle non-zero-offset or non-collapsed selections 2`] = `null`;\n\nexports[`onBackspace removes a preceding atomic block 1`] = `true`;\n\nexports[`onBackspace removes a preceding atomic block 2`] = `false`;\n\nexports[`onBackspace resets the current block type at the start of the first block 1`] = `\nObject {\n  \"characterList\": Array [\n    Object {\n      \"entity\": null,\n      \"style\": Array [],\n    },\n    Object {\n      \"entity\": null,\n      \"style\": Array [],\n    },\n    Object {\n      \"entity\": null,\n      \"style\": Array [],\n    },\n    Object {\n      \"entity\": null,\n      \"style\": Array [],\n    },\n    Object {\n      \"entity\": null,\n      \"style\": Array [],\n    },\n  ],\n  \"data\": Object {},\n  \"depth\": 0,\n  \"key\": \"a\",\n  \"text\": \"Alpha\",\n  \"type\": \"unstyled\",\n}\n`;\n\nexports[`onBackspace resets the current block type if empty 1`] = `\nObject {\n  \"characterList\": Array [],\n  \"data\": Object {},\n  \"depth\": 0,\n  \"key\": \"f\",\n  \"text\": \"\",\n  \"type\": \"unstyled\",\n}\n`;\n\nexports[`onDelete does not handle non-block-end or non-collapsed selections 1`] = `true`;\n\nexports[`onDelete does not handle non-block-end or non-collapsed selections 2`] = `true`;\n\nexports[`onDelete removes a following atomic block 1`] = `false`;\n\nexports[`onDelete removes a following atomic block 2`] = `true`;\n\nexports[`tryToRemoveBlockStyleonDelete breaks out of code block on enter two blank lines 1`] = `\nObject {\n  \"characterList\": Array [\n    Object {\n      \"entity\": null,\n      \"style\": Array [\n        \"ITALIC\",\n      ],\n    },\n    Object {\n      \"entity\": null,\n      \"style\": Array [\n        \"ITALIC\",\n      ],\n    },\n    Object {\n      \"entity\": null,\n      \"style\": Array [\n        \"ITALIC\",\n      ],\n    },\n    Object {\n      \"entity\": null,\n      \"style\": Array [\n        \"ITALIC\",\n      ],\n    },\n    Object {\n      \"entity\": null,\n      \"style\": Array [\n        \"ITALIC\",\n      ],\n    },\n    Object {\n      \"entity\": null,\n      \"style\": Array [\n        \"ITALIC\",\n      ],\n    },\n    Object {\n      \"entity\": null,\n      \"style\": Array [\n        \"ITALIC\",\n      ],\n    },\n  ],\n  \"data\": Object {},\n  \"depth\": 0,\n  \"key\": \"f\",\n  \"text\": \"Charlie\",\n  \"type\": \"blockquote\",\n}\n`;\n"
  },
  {
    "path": "src/model/modifier/exploration/DraftTreeOperations.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * This is unstable and not part of the public API and should not be used by\n * production systems. This file may be update/removed without notice.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\nimport type {BlockMap} from 'BlockMap';\nimport type {BlockNodeKey} from 'BlockNode';\n\nconst ContentBlockNode = require('ContentBlockNode');\nconst DraftTreeInvariants = require('DraftTreeInvariants');\n\nconst generateRandomKey = require('generateRandomKey');\nconst Immutable = require('immutable');\nconst invariant = require('invariant');\n\ntype SiblingInsertPosition = 'previous' | 'next';\n\nconst verifyTree = (tree: BlockMap): void => {\n  if (__DEV__) {\n    invariant(DraftTreeInvariants.isValidTree(tree), 'The tree is not valid');\n  }\n};\n\n/**\n * This is a utility method for setting B as a child of A, ensuring\n * that parent <-> child operations are correctly mirrored\n *\n * The child is inserted at 'position' index in the list\n *\n * The block map returned by this method may not be a valid tree (siblings are\n * unaffected)\n */\nconst updateParentChild = (\n  blockMap: BlockMap,\n  parentKey: string,\n  childKey: string,\n  position: number,\n): BlockMap => {\n  const parent = blockMap.get(parentKey);\n  const child = blockMap.get(childKey);\n  invariant(\n    parent != null && child != null,\n    'parent & child should exist in the block map',\n  );\n  const newBlocks: {[string | BlockNodeKey]: $FlowFixMe} = {};\n  const existingChildren = parent.getChildKeys();\n  invariant(\n    existingChildren != null &&\n      position >= 0 &&\n      position <= existingChildren.count(),\n    'position is not valid for the number of children',\n  );\n\n  // add as parent's child\n  newBlocks[parentKey] = parent.merge({\n    children: existingChildren.splice(position, 0, childKey),\n  });\n\n  let nextSiblingKey = null;\n  let prevSiblingKey = null;\n  // link new child as next sibling to the correct existing child\n  if (position > 0) {\n    prevSiblingKey = existingChildren.get(position - 1);\n    newBlocks[prevSiblingKey] = blockMap.get(prevSiblingKey).merge({\n      nextSibling: childKey,\n    });\n  }\n  // link new child as previous sibling to the correct existing child\n  if (position < existingChildren.count()) {\n    nextSiblingKey = existingChildren.get(position);\n    newBlocks[nextSiblingKey] = blockMap.get(nextSiblingKey).merge({\n      prevSibling: childKey,\n    });\n  }\n  // add parent & siblings to the child\n  newBlocks[childKey] = child.merge({\n    parent: parentKey,\n    prevSibling: prevSiblingKey,\n    nextSibling: nextSiblingKey,\n  });\n  return blockMap.merge(newBlocks);\n};\n\n/**\n * This is a utility method for setting B as the next sibling of A, ensuring\n * that sibling operations are correctly mirrored\n *\n * The block map returned by this method may not be a valid tree (parent/child/\n * other siblings are unaffected)\n */\nconst updateSibling = (\n  blockMap: BlockMap,\n  prevKey: string,\n  nextKey: string,\n): BlockMap => {\n  const prevSibling = blockMap.get(prevKey);\n  const nextSibling = blockMap.get(nextKey);\n  invariant(\n    prevSibling != null && nextSibling != null,\n    'siblings should exist in the block map',\n  );\n  const newBlocks: {[string]: $FlowFixMe} = {};\n  newBlocks[prevKey] = prevSibling.merge({\n    nextSibling: nextKey,\n  });\n  newBlocks[nextKey] = nextSibling.merge({\n    prevSibling: prevKey,\n  });\n  return blockMap.merge(newBlocks);\n};\n\n/**\n * This is a utility method for replacing B by C as a child of A, ensuring\n * that parent <-> child connections between A & C are correctly mirrored\n *\n * The block map returned by this method may not be a valid tree (siblings are\n * unaffected)\n */\nconst replaceParentChild = (\n  blockMap: BlockMap,\n  parentKey: string,\n  existingChildKey: string,\n  newChildKey: string,\n): BlockMap => {\n  const parent = blockMap.get(parentKey);\n  const newChild = blockMap.get(newChildKey);\n  invariant(\n    parent != null && newChild != null,\n    'parent & child should exist in the block map',\n  );\n  const existingChildren = parent.getChildKeys();\n  const newBlocks: {[string]: $FlowFixMe} = {};\n  newBlocks[parentKey] = parent.merge({\n    children: existingChildren.set(\n      existingChildren.indexOf(existingChildKey),\n      newChildKey,\n    ),\n  });\n  newBlocks[newChildKey] = newChild.merge({\n    parent: parentKey,\n  });\n  return blockMap.merge(newBlocks);\n};\n\n/**\n * This is a utility method that abstracts the operation of creating a new parent\n * for a particular node in the block map.\n *\n * This operation respects the tree data invariants - it expects and returns a\n * valid tree.\n */\nconst createNewParent = (blockMap: BlockMap, key: string): BlockMap => {\n  verifyTree(blockMap);\n  const block = blockMap.get(key);\n  invariant(block != null, 'block must exist in block map');\n  const newParent = new ContentBlockNode({\n    key: generateRandomKey(),\n    text: '',\n    depth: block.depth,\n    type: block.type,\n    children: Immutable.List([]),\n  });\n  // add the parent just before the child in the block map\n  let newBlockMap = blockMap\n    .takeUntil(block => block.getKey() === key)\n    .concat(Immutable.OrderedMap([[newParent.getKey(), newParent]]))\n    .concat(blockMap.skipUntil(block => block.getKey() === key));\n  // set parent <-> child connection\n  newBlockMap = updateParentChild(newBlockMap, newParent.getKey(), key, 0);\n  // set siblings & parent for the new parent key to child's siblings & parent\n  const prevSibling = block.getPrevSiblingKey();\n  const nextSibling = block.getNextSiblingKey();\n  const parent = block.getParentKey();\n  if (prevSibling != null) {\n    newBlockMap = updateSibling(newBlockMap, prevSibling, newParent.getKey());\n  }\n  if (nextSibling != null) {\n    newBlockMap = updateSibling(newBlockMap, newParent.getKey(), nextSibling);\n  }\n  if (parent != null) {\n    newBlockMap = replaceParentChild(\n      newBlockMap,\n      parent,\n      key,\n      newParent.getKey(),\n    );\n  }\n  verifyTree(newBlockMap);\n  return newBlockMap;\n};\n\n/**\n * This is a utility method that abstracts the operation of adding a node as the child\n * of its previous or next sibling.\n *\n * The previous (or next) sibling must be a valid parent node.\n *\n * This operation respects the tree data invariants - it expects and returns a\n * valid tree.\n */\nconst updateAsSiblingsChild = (\n  blockMap: BlockMap,\n  key: string,\n  position: SiblingInsertPosition,\n): BlockMap => {\n  verifyTree(blockMap);\n  const block = blockMap.get(key);\n  invariant(block != null, 'block must exist in block map');\n  const newParentKey =\n    position === 'previous'\n      ? block.getPrevSiblingKey()\n      : block.getNextSiblingKey();\n  invariant(newParentKey != null, 'sibling is null');\n  const newParent = blockMap.get(newParentKey);\n  invariant(\n    newParent !== null && newParent.getText() === '',\n    'parent must be a valid node',\n  );\n  let newBlockMap = blockMap;\n  switch (position) {\n    case 'next':\n      newBlockMap = updateParentChild(newBlockMap, newParentKey, key, 0);\n      const prevSibling = block.getPrevSiblingKey();\n      if (prevSibling != null) {\n        newBlockMap = updateSibling(newBlockMap, prevSibling, newParentKey);\n      } else {\n        newBlockMap = newBlockMap.set(\n          newParentKey,\n          newBlockMap.get(newParentKey).merge({prevSibling: null}),\n        );\n      }\n      // we also need to flip the order of the sibling & block in the ordered map\n      // for this case\n      newBlockMap = newBlockMap\n        .takeUntil(block => block.getKey() === key)\n        .concat(\n          Immutable.OrderedMap([\n            [newParentKey, newBlockMap.get(newParentKey)],\n            [key, newBlockMap.get(key)],\n          ]),\n        )\n        .concat(\n          newBlockMap\n            .skipUntil(block => block.getKey() === newParentKey)\n            .slice(1),\n        );\n      break;\n    case 'previous':\n      newBlockMap = updateParentChild(\n        newBlockMap,\n        newParentKey,\n        key,\n        newParent.getChildKeys().count(),\n      );\n      const nextSibling = block.getNextSiblingKey();\n      if (nextSibling != null) {\n        newBlockMap = updateSibling(newBlockMap, newParentKey, nextSibling);\n      } else {\n        newBlockMap = newBlockMap.set(\n          newParentKey,\n          newBlockMap.get(newParentKey).merge({nextSibling: null}),\n        );\n      }\n      break;\n  }\n  // remove the node as a child of its current parent\n  const parentKey = block.getParentKey();\n  if (parentKey != null) {\n    const parent = newBlockMap.get(parentKey);\n    newBlockMap = newBlockMap.set(\n      parentKey,\n      parent.merge({\n        children: parent\n          .getChildKeys()\n          .delete(parent.getChildKeys().indexOf(key)),\n      }),\n    );\n  }\n  verifyTree(newBlockMap);\n  return newBlockMap;\n};\n\n/**\n * This is a utility method that abstracts the operation of moving a node up to become\n * a sibling of its parent. If the operation results in a parent with no children,\n * also delete the parent node.\n *\n * Can only operate on the first or last child (this is an invariant)\n *\n * This operation respects the tree data invariants - it expects and returns a\n * valid tree.\n */\nconst moveChildUp = (blockMap: BlockMap, key: string): BlockMap => {\n  verifyTree(blockMap);\n  const block = blockMap.get(key);\n  invariant(block != null, 'block must exist in block map');\n\n  // if there is no parent, do nothing\n  const parentKey = block.getParentKey();\n  if (parentKey == null) {\n    return blockMap;\n  }\n\n  let parent = blockMap.get(parentKey);\n  invariant(parent !== null, 'parent must exist in block map');\n  let newBlockMap = blockMap;\n  const childIndex = parent.getChildKeys().indexOf(key);\n  invariant(\n    childIndex === 0 || childIndex === parent.getChildKeys().count() - 1,\n    'block is not first or last child of its parent',\n  );\n\n  // If it's the first child, move as previous sibling of parent\n  if (childIndex === 0) {\n    const parentPrevSibling = parent.getPrevSiblingKey();\n    newBlockMap = updateSibling(newBlockMap, key, parentKey);\n    // link to parent's previous sibling\n    if (parentPrevSibling != null) {\n      newBlockMap = updateSibling(newBlockMap, parentPrevSibling, key);\n    }\n    // remove as parent's child\n    parent = newBlockMap.get(parentKey);\n    newBlockMap = newBlockMap.set(\n      parentKey,\n      parent.merge({\n        children: parent.getChildKeys().slice(1),\n      }),\n    );\n    parent = newBlockMap.get(parentKey);\n    // remove as previous sibling of parent's children\n    if (parent.getChildKeys().count() > 0) {\n      const firstChildKey = parent.getChildKeys().first();\n      const firstChild = newBlockMap.get(firstChildKey);\n      newBlockMap = newBlockMap.set(\n        firstChildKey,\n        firstChild.merge({prevSibling: null}),\n      );\n    }\n    // add the node just before its former parent in the block map\n    newBlockMap = newBlockMap\n      .takeUntil(block => block.getKey() === parentKey)\n      .concat(\n        Immutable.OrderedMap([\n          [key, newBlockMap.get(key)],\n          [parentKey, newBlockMap.get(parentKey)],\n        ]),\n      )\n      .concat(newBlockMap.skipUntil(block => block.getKey() === key).slice(1));\n\n    // If it's the last child, move as next sibling of parent\n  } else if (childIndex === parent.getChildKeys().count() - 1) {\n    const parentNextSibling = parent.getNextSiblingKey();\n    newBlockMap = updateSibling(newBlockMap, parentKey, key);\n    // link to parent's next sibling\n    if (parentNextSibling != null) {\n      newBlockMap = updateSibling(newBlockMap, key, parentNextSibling);\n    }\n    // remove as parent's child\n    parent = newBlockMap.get(parentKey);\n    newBlockMap = newBlockMap.set(\n      parentKey,\n      parent.merge({\n        children: parent.getChildKeys().slice(0, -1),\n      }),\n    );\n    parent = newBlockMap.get(parentKey);\n    // remove as next sibling of parent's children\n    if (parent.getChildKeys().count() > 0) {\n      const lastChildKey = parent.getChildKeys().last();\n      const lastChild = newBlockMap.get(lastChildKey);\n      newBlockMap = newBlockMap.set(\n        lastChildKey,\n        lastChild.merge({nextSibling: null}),\n      );\n    }\n  }\n\n  // For both cases, also link to parent's parent\n  const grandparentKey = parent.getParentKey();\n  if (grandparentKey != null) {\n    const grandparentInsertPosition = newBlockMap\n      .get(grandparentKey)\n      .getChildKeys()\n      .findIndex(n => n === parentKey);\n    newBlockMap = updateParentChild(\n      newBlockMap,\n      grandparentKey,\n      key,\n      childIndex === 0\n        ? grandparentInsertPosition\n        : grandparentInsertPosition + 1,\n    );\n  } else {\n    newBlockMap = newBlockMap.set(\n      key,\n      newBlockMap.get(key).merge({parent: null}),\n    );\n  }\n\n  // Delete parent if it has no children\n  parent = newBlockMap.get(parentKey);\n  if (parent.getChildKeys().count() === 0) {\n    const prevSiblingKey = parent.getPrevSiblingKey();\n    const nextSiblingKey = parent.getNextSiblingKey();\n    if (prevSiblingKey != null && nextSiblingKey != null) {\n      newBlockMap = updateSibling(newBlockMap, prevSiblingKey, nextSiblingKey);\n    }\n    if (prevSiblingKey == null && nextSiblingKey != null) {\n      newBlockMap = newBlockMap.set(\n        nextSiblingKey,\n        newBlockMap.get(nextSiblingKey).merge({prevSibling: null}),\n      );\n    }\n    if (nextSiblingKey == null && prevSiblingKey != null) {\n      newBlockMap = newBlockMap.set(\n        prevSiblingKey,\n        newBlockMap.get(prevSiblingKey).merge({nextSibling: null}),\n      );\n    }\n    if (grandparentKey != null) {\n      const grandparent = newBlockMap.get(grandparentKey);\n      const oldChildren = grandparent.getChildKeys();\n      newBlockMap = newBlockMap.set(\n        grandparentKey,\n        grandparent.merge({\n          children: oldChildren.delete(oldChildren.indexOf(parentKey)),\n        }),\n      );\n    }\n\n    newBlockMap = newBlockMap.delete(parentKey);\n  }\n\n  verifyTree(newBlockMap);\n  return newBlockMap;\n};\n\n/**\n * This is a utility method to merge two non-leaf blocks into one. The next block's\n * children are added to the provided block & the next block is deleted.\n *\n * This operation respects the tree data invariants - it expects and returns a\n * valid tree.\n */\nconst mergeBlocks = (blockMap: BlockMap, key: string): BlockMap => {\n  verifyTree(blockMap);\n  // current block must be a non-leaf\n  const block = blockMap.get(key);\n  invariant(block !== null, 'block must exist in block map');\n  invariant(block.getChildKeys().count() > 0, 'block must be a non-leaf');\n  // next block must exist & be a non-leaf\n  const nextBlockKey = block.getNextSiblingKey();\n  invariant(nextBlockKey != null, 'block must have a next block');\n  const nextBlock = blockMap.get(nextBlockKey);\n  invariant(nextBlock != null, 'next block must exist in block map');\n  invariant(\n    nextBlock.getChildKeys().count() > 0,\n    'next block must be a non-leaf',\n  );\n\n  const childKeys = block.getChildKeys().concat(nextBlock.getChildKeys());\n  let newBlockMap = blockMap.set(\n    key,\n    block.merge({\n      nextSibling: nextBlock.getNextSiblingKey(),\n      children: childKeys,\n    }),\n  );\n  newBlockMap = newBlockMap.merge(\n    Immutable.OrderedMap(\n      childKeys.map((k, i) => [\n        k,\n        blockMap.get(k).merge({\n          parent: key,\n          prevSibling: i - 1 < 0 ? null : childKeys.get(i - 1),\n          nextSibling:\n            i + 1 === childKeys.count() ? null : childKeys.get(i + 1),\n        }),\n      ]),\n    ),\n  );\n  newBlockMap = newBlockMap.delete(nextBlockKey);\n\n  const nextNextBlockKey = nextBlock.getNextSiblingKey();\n  if (nextNextBlockKey != null) {\n    newBlockMap = newBlockMap.set(\n      nextNextBlockKey,\n      blockMap.get(nextNextBlockKey).merge({prevSibling: key}),\n    );\n  }\n  verifyTree(newBlockMap);\n  return newBlockMap;\n};\n\nmodule.exports = {\n  updateParentChild,\n  replaceParentChild,\n  updateSibling,\n  createNewParent,\n  updateAsSiblingsChild,\n  moveChildUp,\n  mergeBlocks,\n};\n"
  },
  {
    "path": "src/model/modifier/exploration/NestedRichTextEditorUtil.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * This is unstable and not part of the public API and should not be used by\n * production systems. This file may be update/removed without notice.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\nimport type {BlockMap} from 'BlockMap';\nimport type ContentState from 'ContentState';\nimport type {DraftBlockType} from 'DraftBlockType';\nimport type {DraftEditorCommand} from 'DraftEditorCommand';\nimport type {DataObjectForLink, RichTextUtils} from 'RichTextUtils';\nimport type SelectionState from 'SelectionState';\nimport type URI from 'URI';\n\nconst ContentBlockNode = require('ContentBlockNode');\nconst DraftModifier = require('DraftModifier');\nconst DraftTreeOperations = require('DraftTreeOperations');\nconst EditorState = require('EditorState');\nconst RichTextEditorUtil = require('RichTextEditorUtil');\n\nconst adjustBlockDepthForContentState = require('adjustBlockDepthForContentState');\nconst generateRandomKey = require('generateRandomKey');\nconst invariant = require('invariant');\n\n// Eventually we could allow to control this list by either allowing user configuration\n// and/or a schema in conjunction to DraftBlockRenderMap\nconst NESTING_DISABLED_TYPES = ['code-block', 'atomic'];\n\nconst NestedRichTextEditorUtil: RichTextUtils = {\n  handleKeyCommand: (\n    editorState: EditorState,\n    command: DraftEditorCommand | string,\n  ): ?EditorState => {\n    switch (command) {\n      case 'bold':\n        return NestedRichTextEditorUtil.toggleInlineStyle(editorState, 'BOLD');\n      case 'italic':\n        return NestedRichTextEditorUtil.toggleInlineStyle(\n          editorState,\n          'ITALIC',\n        );\n      case 'underline':\n        return NestedRichTextEditorUtil.toggleInlineStyle(\n          editorState,\n          'UNDERLINE',\n        );\n      case 'code':\n        return NestedRichTextEditorUtil.toggleCode(editorState);\n      case 'backspace':\n      case 'backspace-word':\n      case 'backspace-to-start-of-line':\n        return NestedRichTextEditorUtil.onBackspace(editorState);\n      case 'delete':\n      case 'delete-word':\n      case 'delete-to-end-of-block':\n        return NestedRichTextEditorUtil.onDelete(editorState);\n      default:\n        // they may have custom editor commands; ignore those\n        return null;\n    }\n  },\n\n  onDelete: (editorState: EditorState): ?EditorState => {\n    const selection = editorState.getSelection();\n    if (!selection.isCollapsed()) {\n      return null;\n    }\n\n    const content = editorState.getCurrentContent();\n    const startKey = selection.getStartKey();\n    const block = content.getBlockForKey(startKey);\n    const length = block.getLength();\n\n    // The cursor is somewhere within the text. Behave normally.\n    if (selection.getStartOffset() < length) {\n      return null;\n    }\n\n    const blockAfter = content.getBlockAfter(startKey);\n\n    if (!blockAfter || blockAfter.getType() !== 'atomic') {\n      return null;\n    }\n\n    const atomicBlockTarget = selection.merge({\n      focusKey: blockAfter.getKey(),\n      focusOffset: blockAfter.getLength(),\n    });\n\n    const withoutAtomicBlock = DraftModifier.removeRange(\n      content,\n      atomicBlockTarget,\n      'forward',\n    );\n\n    if (withoutAtomicBlock !== content) {\n      return EditorState.push(editorState, withoutAtomicBlock, 'remove-range');\n    }\n\n    return null;\n  },\n\n  /**\n   * Ensures that if on the beginning of unstyled block and first child of\n   * a nested parent we add its text to the neareast previous leaf node\n   */\n  onBackspace: (editorState: EditorState): ?EditorState => {\n    const selection = editorState.getSelection();\n    const content = editorState.getCurrentContent();\n    const currentBlock = content.getBlockForKey(selection.getStartKey());\n    const previousBlockKey = currentBlock.getPrevSiblingKey();\n\n    if (\n      !selection.isCollapsed() ||\n      selection.getAnchorOffset() ||\n      selection.getFocusOffset() ||\n      (currentBlock.getType() === 'unstyled' &&\n        previousBlockKey &&\n        content.getBlockForKey(previousBlockKey).getType() !== 'atomic')\n    ) {\n      return null;\n    }\n\n    const startKey = selection.getStartKey();\n    const blockBefore = content.getBlockBefore(startKey);\n\n    // we want to delete that block completely\n    if (blockBefore && blockBefore.getType() === 'atomic') {\n      const withoutAtomicBlock = DraftModifier.removeRange(\n        content,\n        selection.merge({\n          focusKey: blockBefore.getKey(),\n          focusOffset: blockBefore.getText().length,\n          anchorKey: startKey,\n          anchorOffset: content.getBlockForKey(startKey).getText().length,\n          isBackward: false,\n        }),\n        'forward',\n      ).merge({\n        selectionAfter: selection,\n      });\n\n      if (withoutAtomicBlock !== content) {\n        return EditorState.push(\n          editorState,\n          withoutAtomicBlock,\n          'remove-range',\n        );\n      }\n    }\n\n    // if we have a next sibling we should not allow the normal backspace\n    // behaviour of moving this text into its parent\n    // if (currentBlock.getPrevSiblingKey()) {\n    //  return editorState;\n    // }\n\n    // If that doesn't succeed, try to remove the current block style.\n    const withoutBlockStyle =\n      NestedRichTextEditorUtil.tryToRemoveBlockStyle(editorState);\n\n    if (withoutBlockStyle) {\n      return EditorState.push(\n        editorState,\n        withoutBlockStyle,\n        withoutBlockStyle.getBlockMap().get(currentBlock.getKey()).getType() ===\n          'unstyled'\n          ? 'change-block-type'\n          : 'adjust-depth',\n      );\n    }\n\n    return null;\n  },\n\n  // Todo (T32099101)\n  // onSplitNestedBlock() {},\n\n  // Todo (T32099101)\n  // onSplitParent() {},\n\n  /**\n   * Ensures that we can create nested blocks by changing the block type of\n   * a ranged selection\n   */\n  toggleBlockType: (\n    editorState: EditorState,\n    blockType: DraftBlockType,\n  ): EditorState => {\n    const selection = editorState.getSelection();\n    const content = editorState.getCurrentContent();\n    const currentBlock = content.getBlockForKey(selection.getStartKey());\n    const haveChildren = !currentBlock.getChildKeys().isEmpty();\n    const isSelectionCollapsed = selection.isCollapsed();\n    const isMultiBlockSelection =\n      selection.getAnchorKey() !== selection.getFocusKey();\n    const isUnsupportedNestingBlockType =\n      NESTING_DISABLED_TYPES.includes(blockType);\n    const isCurrentBlockOfUnsupportedNestingBlockType =\n      NESTING_DISABLED_TYPES.includes(currentBlock.getType());\n\n    // we don't allow this operations to avoid corrupting the document data model\n    // to make sure that non nested blockTypes wont inherit children\n    if (\n      (isMultiBlockSelection || haveChildren) &&\n      isUnsupportedNestingBlockType\n    ) {\n      return editorState;\n    }\n\n    // we can treat this operations the same way as we would for flat data structures\n    if (\n      isCurrentBlockOfUnsupportedNestingBlockType ||\n      isSelectionCollapsed ||\n      isUnsupportedNestingBlockType ||\n      isMultiBlockSelection ||\n      currentBlock.getType() === blockType ||\n      !currentBlock.getChildKeys().isEmpty()\n    ) {\n      return RichTextEditorUtil.toggleBlockType(editorState, blockType);\n    }\n\n    // TODO\n    // if we have full range selection on the block:\n    //   extract text and insert a block after it with the text as its content\n    // else\n    //   split the block into before range and after unstyled blocks\n    //\n    return editorState;\n  },\n\n  currentBlockContainsLink: (editorState: EditorState): boolean => {\n    const selection = editorState.getSelection();\n    const contentState = editorState.getCurrentContent();\n    return contentState\n      .getBlockForKey(selection.getAnchorKey())\n      .getCharacterList()\n      .slice(selection.getStartOffset(), selection.getEndOffset())\n      .some(v => {\n        const entity = v.getEntity();\n        return !!entity && contentState.getEntity(entity).getType() === 'LINK';\n      });\n  },\n\n  getCurrentBlockType: (editorState: EditorState): DraftBlockType => {\n    const selection = editorState.getSelection();\n    return editorState\n      .getCurrentContent()\n      .getBlockForKey(selection.getStartKey())\n      .getType();\n  },\n\n  getDataObjectForLinkURL: (uri: URI): DataObjectForLink => {\n    return {url: uri.toString()};\n  },\n\n  insertSoftNewline: (editorState: EditorState): EditorState => {\n    const contentState = DraftModifier.insertText(\n      editorState.getCurrentContent(),\n      editorState.getSelection(),\n      '\\n',\n      editorState.getCurrentInlineStyle(),\n      null,\n    );\n\n    const newEditorState = EditorState.push(\n      editorState,\n      contentState,\n      'insert-characters',\n    );\n\n    return EditorState.forceSelection(\n      newEditorState,\n      contentState.getSelectionAfter(),\n    );\n  },\n\n  onTab: (\n    event: SyntheticKeyboardEvent<>,\n    editorState: EditorState,\n  ): EditorState => {\n    const selection = editorState.getSelection();\n    const key = selection.getAnchorKey();\n    if (key !== selection.getFocusKey()) {\n      return editorState;\n    }\n\n    let content = editorState.getCurrentContent();\n    const block = content.getBlockForKey(key);\n    const type = block.getType();\n    if (type !== 'unordered-list-item' && type !== 'ordered-list-item') {\n      return editorState;\n    }\n\n    event.preventDefault();\n\n    // implement nested tree behaviour for onTab\n    let blockMap = editorState.getCurrentContent().getBlockMap();\n    const prevSiblingKey = block.getPrevSiblingKey();\n    const nextSiblingKey = block.getNextSiblingKey();\n    if (!event.shiftKey) {\n      // if there is no previous sibling, we do nothing\n      if (prevSiblingKey == null) {\n        return editorState;\n      }\n      // if previous sibling is a non-leaf move node as child of previous sibling\n      const prevSibling = blockMap.get(prevSiblingKey);\n      const nextSibling =\n        nextSiblingKey != null ? blockMap.get(nextSiblingKey) : null;\n      const prevSiblingNonLeaf =\n        prevSibling != null && prevSibling.getChildKeys().count() > 0;\n      const nextSiblingNonLeaf =\n        nextSibling != null && nextSibling.getChildKeys().count() > 0;\n      if (prevSiblingNonLeaf) {\n        blockMap = DraftTreeOperations.updateAsSiblingsChild(\n          blockMap,\n          key,\n          'previous',\n        );\n        // if next sibling is also non-leaf, merge the previous & next siblings\n        if (nextSiblingNonLeaf) {\n          blockMap = DraftTreeOperations.mergeBlocks(blockMap, prevSiblingKey);\n        }\n        // else, if only next sibling is non-leaf move node as child of next sibling\n      } else if (nextSiblingNonLeaf) {\n        blockMap = DraftTreeOperations.updateAsSiblingsChild(\n          blockMap,\n          key,\n          'next',\n        );\n        // if none of the siblings are non-leaf, we need to create a new parent\n      } else {\n        blockMap = DraftTreeOperations.createNewParent(blockMap, key);\n      }\n      // on un-tab\n    } else {\n      // if the block isn't nested, do nothing\n      if (block.getParentKey() == null) {\n        return editorState;\n      }\n      blockMap = onUntab(blockMap, block);\n    }\n    content = editorState.getCurrentContent().merge({\n      blockMap,\n    });\n\n    const withAdjustment = adjustBlockDepthForContentState(\n      content,\n      selection,\n      event.shiftKey ? -1 : 1,\n    );\n\n    return EditorState.push(editorState, withAdjustment, 'adjust-depth');\n  },\n\n  toggleCode: (editorState: EditorState): EditorState => {\n    const selection = editorState.getSelection();\n    const anchorKey = selection.getAnchorKey();\n    const focusKey = selection.getFocusKey();\n\n    if (selection.isCollapsed() || anchorKey !== focusKey) {\n      return RichTextEditorUtil.toggleBlockType(editorState, 'code-block');\n    }\n\n    return RichTextEditorUtil.toggleInlineStyle(editorState, 'CODE');\n  },\n\n  /**\n   * Toggle the specified inline style for the selection. If the\n   * user's selection is collapsed, apply or remove the style for the\n   * internal state. If it is not collapsed, apply the change directly\n   * to the document state.\n   */\n  toggleInlineStyle: (\n    editorState: EditorState,\n    inlineStyle: string,\n  ): EditorState => {\n    const selection = editorState.getSelection();\n    const currentStyle = editorState.getCurrentInlineStyle();\n\n    // If the selection is collapsed, toggle the specified style on or off and\n    // set the result as the new inline style override. This will then be\n    // used as the inline style for the next character to be inserted.\n    if (selection.isCollapsed()) {\n      return EditorState.setInlineStyleOverride(\n        editorState,\n        currentStyle.has(inlineStyle)\n          ? currentStyle.remove(inlineStyle)\n          : currentStyle.add(inlineStyle),\n      );\n    }\n\n    // If characters are selected, immediately apply or remove the\n    // inline style on the document state itself.\n    const content = editorState.getCurrentContent();\n    let newContent;\n\n    // If the style is already present for the selection range, remove it.\n    // Otherwise, apply it.\n    if (currentStyle.has(inlineStyle)) {\n      newContent = DraftModifier.removeInlineStyle(\n        content,\n        selection,\n        inlineStyle,\n      );\n    } else {\n      newContent = DraftModifier.applyInlineStyle(\n        content,\n        selection,\n        inlineStyle,\n      );\n    }\n\n    return EditorState.push(editorState, newContent, 'change-inline-style');\n  },\n\n  toggleLink: (\n    editorState: EditorState,\n    targetSelection: SelectionState,\n    entityKey: ?string,\n  ): EditorState => {\n    const withoutLink = DraftModifier.applyEntity(\n      editorState.getCurrentContent(),\n      targetSelection,\n      entityKey,\n    );\n\n    return EditorState.push(editorState, withoutLink, 'apply-entity');\n  },\n\n  /**\n   * When a collapsed cursor is at the start of a styled block, changes block\n   * type to 'unstyled'. Returns null if selection does not meet that criteria.\n   */\n  tryToRemoveBlockStyle: (editorState: EditorState): ?ContentState => {\n    const selection = editorState.getSelection();\n    const offset = selection.getAnchorOffset();\n    if (selection.isCollapsed() && offset === 0) {\n      const key = selection.getAnchorKey();\n      const content = editorState.getCurrentContent();\n      const block = content.getBlockForKey(key);\n\n      const type = block.getType();\n      const blockBefore = content.getBlockBefore(key);\n      if (\n        type === 'code-block' &&\n        blockBefore &&\n        blockBefore.getType() === 'code-block' &&\n        blockBefore.getLength() !== 0\n      ) {\n        return null;\n      }\n\n      const depth = block.getDepth();\n      if (type !== 'unstyled') {\n        if (\n          (type === 'unordered-list-item' || type === 'ordered-list-item') &&\n          depth > 0\n        ) {\n          let newBlockMap = onUntab(content.getBlockMap(), block);\n          newBlockMap = newBlockMap.set(\n            key,\n            newBlockMap.get(key).merge({depth: depth - 1}),\n          );\n          return content.merge({blockMap: newBlockMap});\n        }\n        return DraftModifier.setBlockType(content, selection, 'unstyled');\n      }\n    }\n    return null;\n  },\n};\n\nconst onUntab = (blockMap: BlockMap, block: ContentBlockNode): BlockMap => {\n  const key = block.getKey();\n  const parentKey = block.getParentKey();\n  const nextSiblingKey = block.getNextSiblingKey();\n  if (parentKey == null) {\n    return blockMap;\n  }\n  const parent = blockMap.get(parentKey);\n  const existingChildren = parent.getChildKeys();\n  const blockIndex = existingChildren.indexOf(key);\n  if (blockIndex === 0 || blockIndex === existingChildren.count() - 1) {\n    blockMap = DraftTreeOperations.moveChildUp(blockMap, key);\n  } else {\n    // split the block into [0, blockIndex] in parent & the rest in a new block\n    const prevChildren = existingChildren.slice(0, blockIndex + 1);\n    const nextChildren = existingChildren.slice(blockIndex + 1);\n    blockMap = blockMap.set(parentKey, parent.merge({children: prevChildren}));\n    const newBlock = new ContentBlockNode({\n      key: generateRandomKey(),\n      text: '',\n      depth: parent.getDepth(),\n      type: parent.getType(),\n      children: nextChildren,\n      parent: parent.getParentKey(),\n    });\n    // add new block just before its the original next sibling in the block map\n    // TODO(T33894878): Remove the map reordering code & fix converter after launch\n    invariant(nextSiblingKey != null, 'block must have a next sibling here');\n    const blocks = blockMap.toSeq();\n    blockMap = blocks\n      .takeUntil(block => block.getKey() === nextSiblingKey)\n      .concat(\n        [[newBlock.getKey(), newBlock]],\n        blocks.skipUntil(block => block.getKey() === nextSiblingKey),\n      )\n      .toOrderedMap();\n\n    // set the nextChildren's parent to the new block\n    blockMap = blockMap.map(block =>\n      nextChildren.includes(block.getKey())\n        ? block.merge({parent: newBlock.getKey()})\n        : block,\n    );\n    // update the next/previous pointers for the children at the split\n    blockMap = blockMap\n      .set(key, block.merge({nextSibling: null}))\n      .set(\n        nextSiblingKey,\n        blockMap.get(nextSiblingKey).merge({prevSibling: null}),\n      );\n    const parentNextSiblingKey = parent.getNextSiblingKey();\n    if (parentNextSiblingKey != null) {\n      blockMap = DraftTreeOperations.updateSibling(\n        blockMap,\n        newBlock.getKey(),\n        parentNextSiblingKey,\n      );\n    }\n    blockMap = DraftTreeOperations.updateSibling(\n      blockMap,\n      parentKey,\n      newBlock.getKey(),\n    );\n    blockMap = DraftTreeOperations.moveChildUp(blockMap, key);\n  }\n\n  // on untab, we also want to unnest any sibling blocks that become two levels deep\n  // ensure that block's old parent does not have a non-leaf as its first child.\n  let childWasUntabbed = false;\n  if (parentKey != null) {\n    let parent = blockMap.get(parentKey);\n    while (parent != null) {\n      const children = parent.getChildKeys();\n      const firstChildKey = children.first();\n      invariant(firstChildKey != null, 'parent must have at least one child');\n      const firstChild = blockMap.get(firstChildKey);\n      if (firstChild.getChildKeys().count() === 0) {\n        break;\n      } else {\n        blockMap = DraftTreeOperations.moveChildUp(blockMap, firstChildKey);\n        parent = blockMap.get(parentKey);\n        childWasUntabbed = true;\n      }\n    }\n  }\n\n  // now, we may be in a state with two non-leaf blocks of the same type\n  // next to each other\n  if (childWasUntabbed && parentKey != null) {\n    const parent = blockMap.get(parentKey);\n    const prevSiblingKey =\n      parent != null // parent may have been deleted\n        ? parent.getPrevSiblingKey()\n        : null;\n    if (prevSiblingKey != null && parent.getChildKeys().count() > 0) {\n      const prevSibling = blockMap.get(prevSiblingKey);\n      if (prevSibling != null && prevSibling.getChildKeys().count() > 0) {\n        blockMap = DraftTreeOperations.mergeBlocks(blockMap, prevSiblingKey);\n      }\n    }\n  }\n  return blockMap;\n};\n\nmodule.exports = NestedRichTextEditorUtil;\n"
  },
  {
    "path": "src/model/modifier/exploration/__tests__/DraftTreeOperations-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\njest.mock('generateRandomKey');\n\nconst ContentBlockNode = require('ContentBlockNode');\nconst DraftTreeOperations = require('DraftTreeOperations');\n\nconst Immutable = require('immutable');\nconst blockMap1 = Immutable.OrderedMap({\n  A: new ContentBlockNode({\n    key: 'A',\n    parent: null,\n    text: 'alpha',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'X',\n  }),\n  X: new ContentBlockNode({\n    key: 'X',\n    parent: null,\n    text: '',\n    children: Immutable.List(['B', 'C']),\n    prevSibling: 'A',\n    nextSibling: 'D',\n  }),\n  B: new ContentBlockNode({\n    key: 'B',\n    parent: 'X',\n    text: 'beta',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'C',\n  }),\n  C: new ContentBlockNode({\n    key: 'C',\n    parent: 'X',\n    text: 'charlie',\n    children: Immutable.List([]),\n    prevSibling: 'B',\n    nextSibling: null,\n  }),\n  D: new ContentBlockNode({\n    key: 'D',\n    parent: null,\n    text: 'delta',\n    children: Immutable.List([]),\n    prevSibling: 'X',\n    nextSibling: null,\n  }),\n});\n\ntest('test adding a child to parent at position 0 (first)', () => {\n  let newBlockMap = DraftTreeOperations.updateParentChild(\n    blockMap1,\n    'X',\n    'D',\n    0,\n  );\n  newBlockMap = newBlockMap.merge({\n    X: newBlockMap.get('X').merge({\n      nextSibling: null,\n    }),\n  });\n  expect(newBlockMap).toMatchSnapshot();\n});\n\ntest('test adding a child to parent at position 1', () => {\n  let newBlockMap = DraftTreeOperations.updateParentChild(\n    blockMap1,\n    'X',\n    'D',\n    1,\n  );\n  newBlockMap = newBlockMap.merge({\n    X: newBlockMap.get('X').merge({\n      nextSibling: null,\n    }),\n  });\n  expect(newBlockMap).toMatchSnapshot();\n});\n\ntest('test adding a child to parent at last position', () => {\n  let newBlockMap = DraftTreeOperations.updateParentChild(\n    blockMap1,\n    'X',\n    'D',\n    2,\n  );\n  newBlockMap = newBlockMap.merge({\n    X: newBlockMap.get('X').merge({\n      nextSibling: null,\n    }),\n  });\n  expect(newBlockMap).toMatchSnapshot();\n});\n\ntest('test adding a sibling', () => {\n  let newBlockMap = DraftTreeOperations.updateSibling(blockMap1, 'D', 'C');\n  newBlockMap = newBlockMap.merge({\n    B: newBlockMap.get('B').merge({\n      nextSibling: null,\n    }),\n    C: newBlockMap.get('C').merge({\n      parent: null,\n    }),\n    X: newBlockMap.get('X').merge({\n      children: ['B'],\n    }),\n  });\n  expect(newBlockMap).toMatchSnapshot();\n});\n\ntest(\"test replacing a parent's child\", () => {\n  let newBlockMap = DraftTreeOperations.replaceParentChild(\n    blockMap1,\n    'X',\n    'C',\n    'D',\n  );\n  newBlockMap = DraftTreeOperations.updateSibling(newBlockMap, 'X', 'C');\n  newBlockMap = DraftTreeOperations.updateSibling(newBlockMap, 'B', 'D');\n  expect(newBlockMap).toMatchSnapshot();\n});\n\nconst blockMap2 = Immutable.OrderedMap({\n  A: new ContentBlockNode({\n    key: 'A',\n    parent: null,\n    text: 'alpha',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'X',\n  }),\n  X: new ContentBlockNode({\n    key: 'X',\n    parent: null,\n    text: '',\n    children: Immutable.List([]),\n    prevSibling: 'A',\n    nextSibling: 'B',\n  }),\n  B: new ContentBlockNode({\n    key: 'B',\n    parent: null,\n    text: 'beta',\n    children: Immutable.List([]),\n    prevSibling: 'X',\n    nextSibling: 'C',\n  }),\n  C: new ContentBlockNode({\n    key: 'C',\n    parent: null,\n    text: 'charlie',\n    children: Immutable.List([]),\n    prevSibling: 'B',\n    nextSibling: null,\n  }),\n});\n\ntest('test adding an only child to parent', () => {\n  let newBlockMap = DraftTreeOperations.updateParentChild(\n    blockMap2,\n    'X',\n    'C',\n    0,\n  );\n  newBlockMap = newBlockMap.merge({\n    B: newBlockMap.get('B').merge({\n      nextSibling: null,\n    }),\n  });\n  expect(newBlockMap).toMatchSnapshot();\n});\n\nconst blockMap3 = Immutable.OrderedMap({\n  A: new ContentBlockNode({\n    key: 'A',\n    parent: null,\n    text: 'alpha',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'B',\n  }),\n  B: new ContentBlockNode({\n    key: 'B',\n    parent: null,\n    text: 'beta',\n    children: Immutable.List([]),\n    prevSibling: 'A',\n    nextSibling: 'C',\n  }),\n  C: new ContentBlockNode({\n    key: 'C',\n    parent: null,\n    text: 'charlie',\n    children: Immutable.List([]),\n    prevSibling: 'B',\n    nextSibling: null,\n  }),\n});\n\ntest('test creating a new parent 1', () => {\n  expect(DraftTreeOperations.createNewParent(blockMap3, 'B')).toMatchSnapshot();\n});\n\ntest('test creating a new parent 2', () => {\n  expect(DraftTreeOperations.createNewParent(blockMap1, 'C')).toMatchSnapshot();\n});\n\ntest(\"test creating a updating node to become next sibling's child 1\", () => {\n  expect(\n    DraftTreeOperations.updateAsSiblingsChild(blockMap1, 'A', 'next'),\n  ).toMatchSnapshot();\n});\n\nconst blockMap4 = Immutable.OrderedMap({\n  A: new ContentBlockNode({\n    key: 'A',\n    parent: null,\n    text: 'alpha',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'B',\n  }),\n  B: new ContentBlockNode({\n    key: 'B',\n    parent: null,\n    text: 'beta',\n    children: Immutable.List([]),\n    prevSibling: 'A',\n    nextSibling: 'X',\n  }),\n  X: new ContentBlockNode({\n    key: 'X',\n    parent: null,\n    text: '',\n    children: Immutable.List(['C']),\n    prevSibling: 'B',\n    nextSibling: 'D',\n  }),\n  C: new ContentBlockNode({\n    key: 'C',\n    parent: 'X',\n    text: 'charlie',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: null,\n  }),\n  D: new ContentBlockNode({\n    key: 'D',\n    parent: null,\n    text: 'delta',\n    children: Immutable.List([]),\n    prevSibling: 'X',\n    nextSibling: null,\n  }),\n});\n\ntest(\"test creating a updating node to become next sibling's child 2\", () => {\n  expect(\n    DraftTreeOperations.updateAsSiblingsChild(blockMap4, 'B', 'next'),\n  ).toMatchSnapshot();\n});\n\nconst blockMap5 = Immutable.OrderedMap({\n  X: new ContentBlockNode({\n    key: 'X',\n    parent: null,\n    text: '',\n    children: Immutable.List(['A', 'B', 'Y']),\n    prevSibling: null,\n    nextSibling: null,\n  }),\n  A: new ContentBlockNode({\n    key: 'A',\n    parent: 'X',\n    text: 'alpha',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'B',\n  }),\n  B: new ContentBlockNode({\n    key: 'B',\n    parent: 'X',\n    text: 'beta',\n    children: Immutable.List([]),\n    prevSibling: 'A',\n    nextSibling: 'Y',\n  }),\n  Y: new ContentBlockNode({\n    key: 'Y',\n    parent: 'X',\n    text: '',\n    children: Immutable.List(['C']),\n    prevSibling: 'B',\n    nextSibling: null,\n  }),\n  C: new ContentBlockNode({\n    key: 'C',\n    parent: 'Y',\n    text: 'charlie',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: null,\n  }),\n});\n\ntest(\"test creating a updating node to become next sibling's child 3\", () => {\n  expect(\n    DraftTreeOperations.updateAsSiblingsChild(blockMap5, 'B', 'next'),\n  ).toMatchSnapshot();\n});\n\ntest(\"test creating a updating node to become previous sibling's child 1\", () => {\n  expect(\n    DraftTreeOperations.updateAsSiblingsChild(blockMap1, 'D', 'previous'),\n  ).toMatchSnapshot();\n});\n\nconst blockMap6 = Immutable.OrderedMap({\n  A: new ContentBlockNode({\n    key: 'A',\n    parent: null,\n    text: 'alpha',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'X',\n  }),\n  X: new ContentBlockNode({\n    key: 'X',\n    parent: null,\n    text: '',\n    children: Immutable.List(['B']),\n    prevSibling: 'A',\n    nextSibling: 'C',\n  }),\n  B: new ContentBlockNode({\n    key: 'B',\n    parent: 'X',\n    text: 'beta',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: null,\n  }),\n  C: new ContentBlockNode({\n    key: 'C',\n    parent: null,\n    text: 'charlie',\n    children: Immutable.List([]),\n    prevSibling: 'X',\n    nextSibling: 'D',\n  }),\n  D: new ContentBlockNode({\n    key: 'D',\n    parent: null,\n    text: 'delta',\n    children: Immutable.List([]),\n    prevSibling: 'C',\n    nextSibling: null,\n  }),\n});\n\ntest(\"test creating a updating node to become previous sibling's child 2\", () => {\n  expect(\n    DraftTreeOperations.updateAsSiblingsChild(blockMap6, 'C', 'previous'),\n  ).toMatchSnapshot();\n});\n\ntest('test moving child up with no parent - no-op', () => {\n  expect(DraftTreeOperations.moveChildUp(blockMap3, 'B')).toMatchSnapshot();\n});\n\ntest('test moving first child up 1', () => {\n  expect(DraftTreeOperations.moveChildUp(blockMap1, 'B')).toMatchSnapshot();\n});\n\nconst blockMap7 = Immutable.OrderedMap({\n  X: new ContentBlockNode({\n    key: 'X',\n    parent: null,\n    text: '',\n    children: Immutable.List(['A', 'Y']),\n    prevSibling: null,\n    nextSibling: null,\n  }),\n  A: new ContentBlockNode({\n    key: 'A',\n    parent: 'X',\n    text: 'alpha',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'Y',\n  }),\n  Y: new ContentBlockNode({\n    key: 'Y',\n    parent: 'X',\n    text: '',\n    children: Immutable.List(['B', 'C']),\n    prevSibling: 'A',\n    nextSibling: null,\n  }),\n  B: new ContentBlockNode({\n    key: 'B',\n    parent: 'Y',\n    text: 'beta',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'C',\n  }),\n  C: new ContentBlockNode({\n    key: 'C',\n    parent: 'Y',\n    text: 'charlie',\n    children: Immutable.List([]),\n    prevSibling: 'B',\n    nextSibling: null,\n  }),\n});\n\ntest('test moving first child up 2', () => {\n  expect(DraftTreeOperations.moveChildUp(blockMap7, 'B')).toMatchSnapshot();\n});\n\ntest('test moving last child up 1', () => {\n  expect(DraftTreeOperations.moveChildUp(blockMap1, 'C')).toMatchSnapshot();\n});\n\ntest('test moving last child up 2', () => {\n  expect(DraftTreeOperations.moveChildUp(blockMap7, 'C')).toMatchSnapshot();\n});\n\nconst blockMap8 = Immutable.OrderedMap({\n  A: new ContentBlockNode({\n    key: 'A',\n    parent: null,\n    text: 'alpha',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'X',\n  }),\n  X: new ContentBlockNode({\n    key: 'X',\n    parent: null,\n    text: '',\n    children: Immutable.List(['B']),\n    prevSibling: 'A',\n    nextSibling: 'C',\n  }),\n  B: new ContentBlockNode({\n    key: 'B',\n    parent: 'X',\n    text: 'beta',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: null,\n  }),\n  C: new ContentBlockNode({\n    key: 'C',\n    parent: null,\n    text: 'charlie',\n    children: Immutable.List([]),\n    prevSibling: 'X',\n    nextSibling: null,\n  }),\n});\n\ntest('test moving only child up deletes parent 1', () => {\n  expect(DraftTreeOperations.moveChildUp(blockMap8, 'B')).toMatchSnapshot();\n});\n\nconst blockMap9 = Immutable.OrderedMap({\n  X: new ContentBlockNode({\n    key: 'X',\n    parent: null,\n    text: '',\n    children: Immutable.List(['B']),\n    prevSibling: null,\n    nextSibling: 'C',\n  }),\n  B: new ContentBlockNode({\n    key: 'B',\n    parent: 'X',\n    text: 'beta',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: null,\n  }),\n  C: new ContentBlockNode({\n    key: 'C',\n    parent: null,\n    text: 'charlie',\n    children: Immutable.List([]),\n    prevSibling: 'X',\n    nextSibling: null,\n  }),\n});\n\ntest('test moving only child up deletes parent 2', () => {\n  expect(DraftTreeOperations.moveChildUp(blockMap9, 'B')).toMatchSnapshot();\n});\n\nconst blockMap10 = Immutable.OrderedMap({\n  A: new ContentBlockNode({\n    key: 'A',\n    parent: null,\n    text: 'alpha',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'X',\n  }),\n  X: new ContentBlockNode({\n    key: 'X',\n    parent: null,\n    text: '',\n    children: Immutable.List(['B']),\n    prevSibling: 'A',\n    nextSibling: null,\n  }),\n  B: new ContentBlockNode({\n    key: 'B',\n    parent: 'X',\n    text: 'beta',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: null,\n  }),\n});\n\ntest('test moving only child up deletes parent 3', () => {\n  expect(DraftTreeOperations.moveChildUp(blockMap10, 'B')).toMatchSnapshot();\n});\n\nconst blockMap11 = Immutable.OrderedMap({\n  A: new ContentBlockNode({\n    key: 'A',\n    parent: null,\n    text: 'alpha',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'X',\n  }),\n  X: new ContentBlockNode({\n    key: 'X',\n    parent: null,\n    text: '',\n    children: Immutable.List(['B', 'Y']),\n    prevSibling: 'A',\n    nextSibling: null,\n  }),\n  B: new ContentBlockNode({\n    key: 'B',\n    parent: 'X',\n    text: 'beta',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'Y',\n  }),\n  Y: new ContentBlockNode({\n    key: 'Y',\n    parent: 'X',\n    text: '',\n    children: Immutable.List(['C']),\n    prevSibling: 'B',\n    nextSibling: null,\n  }),\n  C: new ContentBlockNode({\n    key: 'C',\n    parent: 'Y',\n    text: 'charlie',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: null,\n  }),\n});\n\ntest('test moving only child up deletes parent 4', () => {\n  expect(DraftTreeOperations.moveChildUp(blockMap11, 'C')).toMatchSnapshot();\n});\n\nconst blockMap12 = Immutable.OrderedMap({\n  A: new ContentBlockNode({\n    key: 'A',\n    parent: null,\n    text: 'alpha',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'X',\n  }),\n  X: new ContentBlockNode({\n    key: 'X',\n    parent: null,\n    text: '',\n    children: Immutable.List(['B', 'C']),\n    prevSibling: 'A',\n    nextSibling: 'Y',\n  }),\n  B: new ContentBlockNode({\n    key: 'B',\n    parent: 'X',\n    text: 'beta',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'C',\n  }),\n  C: new ContentBlockNode({\n    key: 'C',\n    parent: 'X',\n    text: 'charlie',\n    children: Immutable.List([]),\n    prevSibling: 'B',\n    nextSibling: null,\n  }),\n  Y: new ContentBlockNode({\n    key: 'Y',\n    parent: null,\n    text: '',\n    children: Immutable.List(['D', 'E']),\n    prevSibling: 'X',\n    nextSibling: null,\n  }),\n  D: new ContentBlockNode({\n    key: 'D',\n    parent: 'Y',\n    text: 'delta',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'E',\n  }),\n  E: new ContentBlockNode({\n    key: 'E',\n    parent: 'Y',\n    text: 'epsilon',\n    children: Immutable.List([]),\n    prevSibling: 'D',\n    nextSibling: null,\n  }),\n});\n\ntest('test merging blocks', () => {\n  expect(DraftTreeOperations.mergeBlocks(blockMap12, 'X')).toMatchSnapshot();\n});\n"
  },
  {
    "path": "src/model/modifier/exploration/__tests__/NestedRichTextEditorUtil-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @format\n * @oncall draft_js\n */\n\njest.mock('generateRandomKey');\n\nconst AtomicBlockUtils = require('AtomicBlockUtils');\nconst BlockMapBuilder = require('BlockMapBuilder');\nconst ContentBlockNode = require('ContentBlockNode');\nconst EditorState = require('EditorState');\nconst NestedRichTextEditorUtil = require('NestedRichTextEditorUtil');\nconst SelectionState = require('SelectionState');\n\nconst getSampleStateForTesting = require('getSampleStateForTesting');\nconst Immutable = require('immutable');\n\nconst {List} = Immutable;\n\nconst {editorState, contentState, selectionState} = getSampleStateForTesting();\nconst {onBackspace, onDelete, onTab} = NestedRichTextEditorUtil;\n\nconst contentBlockNodes = [\n  new ContentBlockNode({\n    key: 'A',\n    nextSibling: 'B',\n    text: 'Alpha',\n    type: 'blockquote',\n  }),\n  new ContentBlockNode({\n    key: 'B',\n    prevSibling: 'A',\n    nextSibling: 'G',\n    type: 'ordered-list-item',\n    children: List(['C', 'F']),\n  }),\n  new ContentBlockNode({\n    parent: 'B',\n    key: 'C',\n    nextSibling: 'F',\n    type: 'blockquote',\n    children: List(['D', 'E']),\n  }),\n  new ContentBlockNode({\n    parent: 'C',\n    key: 'D',\n    nextSibling: 'E',\n    type: 'header-two',\n    text: 'Delta',\n  }),\n  new ContentBlockNode({\n    parent: 'C',\n    key: 'E',\n    prevSibling: 'D',\n    type: 'unstyled',\n    text: 'Elephant',\n  }),\n  new ContentBlockNode({\n    parent: 'B',\n    key: 'F',\n    prevSibling: 'C',\n    type: 'code-block',\n    text: 'Fire',\n  }),\n  new ContentBlockNode({\n    key: 'G',\n    prevSibling: 'B',\n    nextSibling: 'H',\n    type: 'ordered-list-item',\n    text: 'Gorila',\n  }),\n  new ContentBlockNode({\n    key: 'H',\n    prevSibling: 'G',\n    nextSibling: 'I',\n    text: ' ',\n    type: 'atomic',\n  }),\n  new ContentBlockNode({\n    key: 'I',\n    prevSibling: 'H',\n    text: 'last',\n    type: 'unstyled',\n  }),\n];\n\nconst toggleExperimentalTreeDataSupport = enabled => {\n  jest.doMock('gkx', () => name => {\n    return name === 'draft_tree_data_support' ? enabled : false;\n  });\n};\n\nconst insertAtomicBlock = targetEditorState => {\n  const entityKey = targetEditorState\n    .getCurrentContent()\n    .createEntity('TEST', 'IMMUTABLE', null)\n    .getLastCreatedEntityKey();\n  const character = ' ';\n  const movedSelection = EditorState.moveSelectionToEnd(targetEditorState);\n  return AtomicBlockUtils.insertAtomicBlock(\n    movedSelection,\n    entityKey,\n    character,\n  );\n};\n\nconst assertNestedUtilOperation = (\n  operation,\n  selection = {},\n  content = contentBlockNodes,\n) => {\n  const result = operation(\n    EditorState.forceSelection(\n      EditorState.createWithContent(\n        contentState.set('blockMap', BlockMapBuilder.createFromArray(content)),\n      ),\n      SelectionState.createEmpty(content[0].key).merge(selection),\n    ),\n  );\n\n  const expected =\n    result instanceof EditorState\n      ? result.getCurrentContent().getBlockMap().toJS()\n      : result;\n\n  expect(expected).toMatchSnapshot();\n};\n\ntoggleExperimentalTreeDataSupport(true);\n\ntest(`toggleBlockType does not handle nesting when selection is collapsed`, () => {\n  assertNestedUtilOperation(editorState =>\n    NestedRichTextEditorUtil.toggleBlockType(editorState, 'header-one'),\n  );\n});\n\ntest(`toggleBlockType does not handle nesting for multi block selection`, () => {\n  assertNestedUtilOperation(\n    editorState =>\n      NestedRichTextEditorUtil.toggleBlockType(editorState, 'header-one'),\n    {\n      anchorKey: 'D',\n      focusKey: 'E',\n      focusOffset: contentBlockNodes[4].getLength(),\n    },\n  );\n});\n\ntest(`toggleBlockType does not allow block type change for multi block selection to unsupported type`, () => {\n  assertNestedUtilOperation(\n    editorState =>\n      NestedRichTextEditorUtil.toggleBlockType(editorState, 'code-block'),\n    {\n      anchorKey: 'D',\n      focusKey: 'E',\n      focusOffset: contentBlockNodes[4].getLength(),\n    },\n  );\n});\n\ntest(`toggleBlockType does not handle nesting for blockType: \"atomic\"`, () => {\n  assertNestedUtilOperation(\n    editorState =>\n      NestedRichTextEditorUtil.toggleBlockType(editorState, 'header-one'),\n    {\n      anchorKey: 'H',\n      focusKey: 'H',\n      focusOffset: contentBlockNodes[7].getLength(),\n    },\n  );\n});\n\ntest(`toggleBlockType does not handle nesting for blockType: \"code-block\"`, () => {\n  assertNestedUtilOperation(\n    editorState =>\n      NestedRichTextEditorUtil.toggleBlockType(editorState, 'header-two'),\n    {\n      anchorKey: 'F',\n      focusKey: 'F',\n      focusOffset: contentBlockNodes[5].getLength(),\n    },\n  );\n});\n\ntest(`toggleBlockType does not handle nesting for block that has children`, () => {\n  assertNestedUtilOperation(\n    editorState =>\n      NestedRichTextEditorUtil.toggleBlockType(editorState, 'header-one'),\n    {\n      anchorKey: 'C',\n      focusKey: 'C',\n      focusOffset: contentBlockNodes[2].getLength(),\n    },\n  );\n});\n\ntest(`toggleBlockType does not allow block type change for block that has children to unsupported type`, () => {\n  assertNestedUtilOperation(\n    editorState =>\n      NestedRichTextEditorUtil.toggleBlockType(editorState, 'code-block'),\n    {\n      anchorKey: 'C',\n      focusKey: 'C',\n      focusOffset: contentBlockNodes[2].getLength(),\n    },\n  );\n});\n\n/**\n * Example:\n *\n * Having the cursor on the H1 and trying to change blocktype to unordered-list\n * it should not update h1 instead it should udate its parent block type\n *\n * blockquote > foo\n * should not become\n * blockquote > blockquote > foo\n */\ntest('toggleBlockType does not handle nesting enabled blocks with same blockType', () => {\n  assertNestedUtilOperation(\n    editorState =>\n      NestedRichTextEditorUtil.toggleBlockType(editorState, 'blockquote'),\n    {\n      anchorKey: 'A',\n      focusKey: 'A',\n      focusOffset: contentBlockNodes[0].getLength(),\n    },\n  );\n});\n\n/**\n * Example:\n *\n * Having the cursor on the H1 and trying to change blocktype to unordered-list\n * it should not update h1 instead it should udate its parent block type\n *\n * ordered-list > h1\n * should become\n * unordered-list > h1\n */\n// TODO (T32099101)\ntest('toggleBlockType should change parent block type when changing type for same tag element', () => {\n  expect(true).toBe(true);\n});\n\n/**\n *  Example:\n *\n *  Changing the block type inside a nested enable block that has text should\n *  transfer it's text to a nested unstyled block example\n *\n *  blockquote > ordered-list-item\n *  should become\n *  blockquote > ordered-list-item > unstyled\n */\n// TODO (T32099101)\ntest('toggleBlockType with ranged selection should retain parent type and create a new nested block with text from parent', () => {\n  expect(true).toBe(true);\n});\n\ntest('onBackspace does not handle non-zero-offset selections', () => {\n  assertNestedUtilOperation(editorState => onBackspace(editorState), {\n    anchorKey: 'F',\n    focusKey: 'F',\n    anchorOffset: 2,\n    focusOffset: 2,\n  });\n});\n\ntest('onBackspace does not handle non-collapsed selections', () => {\n  assertNestedUtilOperation(editorState => onBackspace(editorState), {\n    anchorKey: 'F',\n    focusKey: 'F',\n    focusOffset: 2,\n  });\n});\n\ntest('onBackspace resets the current block type if empty', () => {\n  assertNestedUtilOperation(editorState => onBackspace(editorState), {\n    anchorKey: 'F',\n    focusKey: 'F',\n  });\n});\n\ntest('onBackspace removes a preceding atomic block', () => {\n  assertNestedUtilOperation(editorState => onBackspace(editorState), {\n    focusKey: 'I',\n    anchorKey: 'I',\n  });\n});\n\n// TODO (T32099101)\ntest('onBackspace on the start of a leaf unstyled block should remove block and merge text to previous leaf', () => {\n  expect(true).toBe(true);\n});\n\ntest('onDelete is a no-op if its at the end of the blockMap', () => {\n  const lastContentBlock = contentBlockNodes[contentBlockNodes.length - 1];\n  const lastContentBlockKey = lastContentBlock.getKey();\n  const endOfLastContentBlock = lastContentBlock.getLength();\n  assertNestedUtilOperation(editorState => onDelete(editorState), {\n    anchorKey: lastContentBlockKey,\n    anchorOffset: endOfLastContentBlock,\n    focusKey: lastContentBlockKey,\n    focusOffset: lastContentBlockKey,\n  });\n});\n\n// NOTE: We may implement this in the future\ntest('onDelete is a no-op the end of a leaf', () => {\n  const someLeafBlock = contentBlockNodes[3];\n  const someLeafBlockKey = someLeafBlock.getKey();\n  const endOfSomeLeafBlock = someLeafBlock.getLength();\n  assertNestedUtilOperation(editorState => onDelete(editorState), {\n    anchorKey: someLeafBlockKey,\n    anchorOffset: endOfSomeLeafBlock,\n    focusKey: someLeafBlockKey,\n    focusOffset: endOfSomeLeafBlock,\n  });\n});\n\n/**\n * Tests for onTab\n */\nconst contentBlockNodes2 = [\n  new ContentBlockNode({\n    key: 'A',\n    nextSibling: 'B',\n    text: 'Item 1',\n    type: 'ordered-list-item',\n    children: List([]),\n  }),\n  new ContentBlockNode({\n    key: 'B',\n    prevSibling: 'A',\n    nextSibling: 'C',\n    text: 'Item 2',\n    type: 'ordered-list-item',\n    children: List([]),\n  }),\n  new ContentBlockNode({\n    key: 'C',\n    prevSibling: 'B',\n    nextSibling: 'J',\n    text: '',\n    type: 'ordered-list-item',\n    children: List(['D', 'E', 'F', 'I']),\n  }),\n  new ContentBlockNode({\n    key: 'D',\n    parent: 'C',\n    prevSibling: null,\n    nextSibling: 'E',\n    text: 'Item 2a',\n    type: 'ordered-list-item',\n    children: List([]),\n  }),\n  new ContentBlockNode({\n    key: 'E',\n    parent: 'C',\n    prevSibling: 'D',\n    nextSibling: 'F',\n    text: 'Item 2b',\n    type: 'ordered-list-item',\n    children: List([]),\n  }),\n  new ContentBlockNode({\n    key: 'F',\n    parent: 'C',\n    prevSibling: 'E',\n    nextSibling: 'I',\n    text: '',\n    type: 'ordered-list-item',\n    children: List(['G', 'H']),\n  }),\n  new ContentBlockNode({\n    key: 'G',\n    parent: 'F',\n    prevSibling: null,\n    nextSibling: 'H',\n    text: 'Item 2b i',\n    type: 'ordered-list-item',\n    children: List([]),\n  }),\n  new ContentBlockNode({\n    key: 'H',\n    parent: 'F',\n    prevSibling: 'G',\n    nextSibling: null,\n    text: 'Item 2b ii',\n    type: 'ordered-list-item',\n    children: List([]),\n  }),\n  new ContentBlockNode({\n    key: 'I',\n    parent: 'C',\n    prevSibling: 'F',\n    nextSibling: null,\n    text: 'Item 2c',\n    type: 'ordered-list-item',\n    children: List([]),\n  }),\n  new ContentBlockNode({\n    key: 'J',\n    prevSibling: 'C',\n    nextSibling: null,\n    text: 'Item 3',\n    type: 'ordered-list-item',\n    children: List([]),\n  }),\n];\n\ntest('onTab with leaf as previous block & non-leaf as next block merges to the next block', () => {\n  assertNestedUtilOperation(\n    editorState => onTab({preventDefault: () => {}}, editorState),\n    {\n      anchorKey: 'E',\n      focusKey: 'E',\n    },\n    contentBlockNodes2,\n  );\n});\n\ntest('onTab with non-leaf as previous block merges to the previous block', () => {\n  assertNestedUtilOperation(\n    editorState => onTab({preventDefault: () => {}}, editorState),\n    {\n      anchorKey: 'I',\n      focusKey: 'I',\n    },\n    contentBlockNodes2,\n  );\n});\n\ntest('onTab with no previous block does nothing', () => {\n  assertNestedUtilOperation(\n    editorState => onTab({preventDefault: () => {}}, editorState),\n    {\n      anchorKey: 'A',\n      focusKey: 'A',\n    },\n    contentBlockNodes2,\n  );\n});\n\ntest('onTab when siblings are at the same depth creates a new parent', () => {\n  assertNestedUtilOperation(\n    editorState => onTab({preventDefault: () => {}}, editorState),\n    {\n      anchorKey: 'H',\n      focusKey: 'H',\n    },\n    contentBlockNodes2,\n  );\n});\n\nconst contentBlockNodes3 = [\n  new ContentBlockNode({\n    key: 'A',\n    parent: null,\n    text: 'alpha',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'X',\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'X',\n    parent: null,\n    text: '',\n    children: Immutable.List(['B']),\n    prevSibling: 'A',\n    nextSibling: 'C',\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'B',\n    parent: 'X',\n    text: 'beta',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: null,\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'C',\n    parent: null,\n    text: 'charlie',\n    children: Immutable.List([]),\n    prevSibling: 'X',\n    nextSibling: 'Y',\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'Y',\n    parent: null,\n    text: '',\n    children: Immutable.List(['D', 'E']),\n    prevSibling: 'C',\n    nextSibling: null,\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'D',\n    parent: 'Y',\n    text: 'delta',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'E',\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'E',\n    parent: 'Y',\n    text: 'epsilon',\n    children: Immutable.List([]),\n    prevSibling: 'D',\n    nextSibling: null,\n    type: 'ordered-list-item',\n  }),\n];\n\ntest('onTab when both siblings are non-leaf merges blocks 1', () => {\n  assertNestedUtilOperation(\n    editorState => onTab({preventDefault: () => {}}, editorState),\n    {\n      anchorKey: 'C',\n      focusKey: 'C',\n    },\n    contentBlockNodes3,\n  );\n});\n\nconst contentBlockNodes4 = [\n  new ContentBlockNode({\n    key: 'A',\n    parent: null,\n    text: 'alpha',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'X',\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'X',\n    parent: null,\n    text: '',\n    children: Immutable.List(['B', 'Y']),\n    prevSibling: 'A',\n    nextSibling: 'D',\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'B',\n    parent: 'X',\n    text: 'beta',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'Y',\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'Y',\n    parent: 'X',\n    text: '',\n    children: Immutable.List(['C']),\n    prevSibling: 'B',\n    nextSibling: null,\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'C',\n    parent: 'Y',\n    text: 'charlie',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: null,\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'D',\n    parent: null,\n    text: 'delta',\n    children: Immutable.List([]),\n    prevSibling: 'X',\n    nextSibling: 'Z',\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'Z',\n    parent: null,\n    text: '',\n    children: Immutable.List(['E']),\n    prevSibling: 'D',\n    nextSibling: null,\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'E',\n    parent: 'Z',\n    text: 'epsilon',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: null,\n    type: 'ordered-list-item',\n  }),\n];\n\ntest('onTab when both siblings are non-leaf merges blocks 2', () => {\n  assertNestedUtilOperation(\n    editorState => onTab({preventDefault: () => {}}, editorState),\n    {\n      anchorKey: 'D',\n      focusKey: 'D',\n    },\n    contentBlockNodes4,\n  );\n});\n\ntest('onTab (untab) on a block with no parent does nothing', () => {\n  assertNestedUtilOperation(\n    editorState =>\n      onTab({preventDefault: () => {}, shiftKey: true}, editorState),\n    {\n      anchorKey: 'B',\n      focusKey: 'B',\n    },\n    contentBlockNodes2,\n  );\n});\n\ntest('onTab (untab) on a first child moves block as previous sibling of parent', () => {\n  assertNestedUtilOperation(\n    editorState =>\n      onTab({preventDefault: () => {}, shiftKey: true}, editorState),\n    {\n      anchorKey: 'D',\n      focusKey: 'D',\n    },\n    contentBlockNodes2,\n  );\n});\n\ntest('onTab (untab) on a last child moves block as next sibling of parent', () => {\n  assertNestedUtilOperation(\n    editorState =>\n      onTab({preventDefault: () => {}, shiftKey: true}, editorState),\n    {\n      anchorKey: 'H',\n      focusKey: 'H',\n    },\n    contentBlockNodes2,\n  );\n});\n\nconst contentBlockNodes5 = [\n  new ContentBlockNode({\n    key: 'A',\n    nextSibling: 'X',\n    text: 'alpha',\n    type: 'ordered-list-item',\n    children: List([]),\n  }),\n  new ContentBlockNode({\n    key: 'X',\n    prevSibling: 'A',\n    nextSibling: 'G',\n    text: '',\n    type: 'ordered-list-item',\n    children: List(['B', 'C', 'D', 'E', 'F']),\n  }),\n  new ContentBlockNode({\n    key: 'B',\n    parent: 'X',\n    prevSibling: null,\n    nextSibling: 'C',\n    text: 'beta',\n    type: 'ordered-list-item',\n    children: List([]),\n  }),\n  new ContentBlockNode({\n    key: 'C',\n    parent: 'X',\n    prevSibling: 'B',\n    nextSibling: 'D',\n    text: 'charlie',\n    type: 'ordered-list-item',\n    children: List([]),\n  }),\n  new ContentBlockNode({\n    key: 'D',\n    parent: 'X',\n    prevSibling: 'C',\n    nextSibling: 'E',\n    text: 'delta',\n    type: 'ordered-list-item',\n    children: List([]),\n  }),\n  new ContentBlockNode({\n    key: 'E',\n    parent: 'X',\n    prevSibling: 'D',\n    nextSibling: 'F',\n    text: 'epsilon',\n    type: 'ordered-list-item',\n    children: List([]),\n  }),\n  new ContentBlockNode({\n    key: 'F',\n    parent: 'X',\n    prevSibling: 'E',\n    nextSibling: null,\n    text: 'foo',\n    type: 'ordered-list-item',\n    children: List([]),\n  }),\n  new ContentBlockNode({\n    key: 'G',\n    prevSibling: 'X',\n    nextSibling: null,\n    text: 'gamma',\n    type: 'ordered-list-item',\n    children: List([]),\n  }),\n];\n\ntest('onTab (untab) on a middle child splits the block at that child', () => {\n  assertNestedUtilOperation(\n    editorState =>\n      onTab({preventDefault: () => {}, shiftKey: true}, editorState),\n    {\n      anchorKey: 'E',\n      focusKey: 'E',\n    },\n    contentBlockNodes5,\n  );\n});\n\nconst contentBlockNodes6 = [\n  new ContentBlockNode({\n    key: 'A',\n    parent: null,\n    text: 'alpha',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'X',\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'X',\n    parent: null,\n    text: '',\n    children: Immutable.List(['B', 'Y']),\n    prevSibling: 'A',\n    nextSibling: null,\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'B',\n    parent: 'X',\n    text: 'beta',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'Y',\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'Y',\n    parent: 'X',\n    text: '',\n    children: Immutable.List(['C']),\n    prevSibling: 'B',\n    nextSibling: null,\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'C',\n    parent: 'Y',\n    text: 'charlie',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: null,\n    type: 'ordered-list-item',\n  }),\n];\n\ntest('onTab (untab) unnests non-leaf next sibling', () => {\n  assertNestedUtilOperation(\n    editorState =>\n      onTab({preventDefault: () => {}, shiftKey: true}, editorState),\n    {\n      anchorKey: 'B',\n      focusKey: 'B',\n    },\n    contentBlockNodes6,\n  );\n});\n\nconst contentBlockNodes7 = [\n  new ContentBlockNode({\n    key: 'A',\n    parent: null,\n    text: 'alpha',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'X',\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'X',\n    parent: null,\n    text: '',\n    children: Immutable.List(['B', 'Y', 'E']),\n    prevSibling: 'A',\n    nextSibling: null,\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'B',\n    parent: 'X',\n    text: 'beta',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'Y',\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'Y',\n    parent: 'X',\n    text: '',\n    children: Immutable.List(['C', 'D']),\n    prevSibling: 'B',\n    nextSibling: 'E',\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'C',\n    parent: 'Y',\n    text: 'charlie',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'D',\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'D',\n    parent: 'Y',\n    text: 'delta',\n    children: Immutable.List([]),\n    prevSibling: 'C',\n    nextSibling: null,\n    type: 'ordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'E',\n    parent: 'X',\n    text: 'epsilon',\n    children: Immutable.List([]),\n    prevSibling: 'Y',\n    nextSibling: null,\n    type: 'ordered-list-item',\n  }),\n];\n\ntest('onTab (untab) merges adjacent non-leaf blocks', () => {\n  assertNestedUtilOperation(\n    editorState =>\n      onTab({preventDefault: () => {}, shiftKey: true}, editorState),\n    {\n      anchorKey: 'B',\n      focusKey: 'B',\n    },\n    contentBlockNodes7,\n  );\n});\n\n// Some backspace operations have similar behavior to untab\nconst contentBlockNodes8 = [\n  new ContentBlockNode({\n    key: 'A',\n    parent: null,\n    text: 'alpha',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'X',\n    depth: 0,\n    type: 'unordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'X',\n    parent: null,\n    text: '',\n    children: Immutable.List(['B', 'C']),\n    prevSibling: 'A',\n    nextSibling: null,\n    depth: 0,\n    type: 'unordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'B',\n    parent: 'X',\n    text: 'beta',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'C',\n    depth: 1,\n    type: 'unordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'C',\n    parent: 'X',\n    text: '',\n    children: Immutable.List([]),\n    prevSibling: 'B',\n    nextSibling: null,\n    depth: 1,\n    type: 'unordered-list-item',\n  }),\n];\n\ntest('onBackspace at start of nested block unnests it 1', () => {\n  assertNestedUtilOperation(\n    editorState => onBackspace(editorState),\n    {\n      anchorKey: 'C',\n      focusKey: 'C',\n      anchorOffset: 0,\n      focusOffset: 0,\n    },\n    contentBlockNodes8,\n  );\n});\n\nconst contentBlockNodes9 = [\n  new ContentBlockNode({\n    key: 'A',\n    parent: null,\n    text: 'alpha',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'X',\n    depth: 0,\n    type: 'unordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'X',\n    parent: null,\n    text: '',\n    children: Immutable.List(['B', 'Y']),\n    prevSibling: 'A',\n    nextSibling: null,\n    depth: 0,\n    type: 'unordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'B',\n    parent: 'X',\n    text: 'beta',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'Y',\n    depth: 1,\n    type: 'unordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'Y',\n    parent: 'X',\n    text: '',\n    children: Immutable.List(['C', 'D']),\n    prevSibling: 'B',\n    nextSibling: null,\n    depth: 1,\n    type: 'unordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'C',\n    parent: 'Y',\n    text: 'charlie',\n    children: Immutable.List([]),\n    prevSibling: null,\n    nextSibling: 'D',\n    depth: 2,\n    type: 'unordered-list-item',\n  }),\n  new ContentBlockNode({\n    key: 'D',\n    parent: 'Y',\n    text: '',\n    children: Immutable.List([]),\n    prevSibling: 'C',\n    nextSibling: null,\n    depth: 2,\n    type: 'unordered-list-item',\n  }),\n];\n\ntest('onBackspace at start of nested block unnests it 2', () => {\n  assertNestedUtilOperation(\n    editorState => onBackspace(editorState),\n    {\n      anchorKey: 'D',\n      focusKey: 'D',\n      anchorOffset: 0,\n      focusOffset: 0,\n    },\n    contentBlockNodes9,\n  );\n});\n\n// TODO (T32099101)\ntest('onSplitParent must split a nested block retaining parent', () => {\n  expect(true).toBe(true);\n});\n\n/**\n * => Note:\n *\n * The bellow tests are a port from RichTextEditorUtil-test.js to ensure that\n * NestedRichTextEditorUtil can provide the same guarantees as its flat counterpart.\n */\ntest('onDelete does not handle non-block-end or non-collapsed selections', () => {\n  const nonZero = selectionState.merge({anchorOffset: 2, focusOffset: 2});\n  expect(\n    onDelete(EditorState.forceSelection(editorState, nonZero)) === null,\n  ).toMatchSnapshot();\n\n  const nonCollapsed = nonZero.merge({anchorOffset: 0});\n  expect(\n    onDelete(EditorState.forceSelection(editorState, nonCollapsed)) === null,\n  ).toMatchSnapshot();\n});\n\ntest('onDelete removes a following atomic block', () => {\n  const blockSizeBeforeRemove = editorState\n    .getCurrentContent()\n    .getBlockMap().size;\n  const withAtomicBlock = insertAtomicBlock(editorState);\n  const content = withAtomicBlock.getCurrentContent();\n  const atomicKey = content\n    .getBlockMap()\n    .find(block => block.getType() === 'atomic')\n    .getKey();\n\n  const blockBefore = content.getBlockBefore(atomicKey);\n  const keyBefore = blockBefore.getKey();\n  const lengthBefore = blockBefore.getLength();\n\n  const withSelectionAboveAtomic = EditorState.forceSelection(\n    withAtomicBlock,\n    new SelectionState({\n      anchorKey: keyBefore,\n      anchorOffset: lengthBefore,\n      focusKey: keyBefore,\n      focusOffset: lengthBefore,\n    }),\n  );\n\n  const afterDelete = onDelete(withSelectionAboveAtomic);\n  const blockMapAfterDelete = afterDelete.getCurrentContent().getBlockMap();\n\n  expect(\n    blockMapAfterDelete.some(block => block.getType() === 'atomic'),\n  ).toMatchSnapshot();\n\n  expect(\n    blockMapAfterDelete.size === blockSizeBeforeRemove + 1,\n  ).toMatchSnapshot();\n});\n"
  },
  {
    "path": "src/model/modifier/exploration/__tests__/__snapshots__/DraftTreeOperations-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`test adding a child to parent at last position 1`] = `\nImmutable.OrderedMap {\n  \"A\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"X\",\n  },\n  \"X\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"B\",\n      \"C\",\n      \"D\",\n    ],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": null,\n  },\n  \"B\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"C\",\n  },\n  \"C\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"B\",\n    \"nextSibling\": \"D\",\n  },\n  \"D\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"text\": \"delta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"C\",\n    \"nextSibling\": null,\n  },\n}\n`;\n\nexports[`test adding a child to parent at position 0 (first) 1`] = `\nImmutable.OrderedMap {\n  \"A\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"X\",\n  },\n  \"X\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"D\",\n      \"B\",\n      \"C\",\n    ],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": null,\n  },\n  \"B\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"D\",\n    \"nextSibling\": \"C\",\n  },\n  \"C\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"B\",\n    \"nextSibling\": null,\n  },\n  \"D\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"text\": \"delta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"B\",\n  },\n}\n`;\n\nexports[`test adding a child to parent at position 1 1`] = `\nImmutable.OrderedMap {\n  \"A\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"X\",\n  },\n  \"X\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"B\",\n      \"D\",\n      \"C\",\n    ],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": null,\n  },\n  \"B\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"D\",\n  },\n  \"C\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"D\",\n    \"nextSibling\": null,\n  },\n  \"D\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"text\": \"delta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"B\",\n    \"nextSibling\": \"C\",\n  },\n}\n`;\n\nexports[`test adding a sibling 1`] = `\nImmutable.OrderedMap {\n  \"A\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"X\",\n  },\n  \"X\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"B\",\n    ],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": \"D\",\n  },\n  \"B\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": null,\n  },\n  \"C\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"D\",\n    \"nextSibling\": null,\n  },\n  \"D\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"text\": \"delta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"X\",\n    \"nextSibling\": \"C\",\n  },\n}\n`;\n\nexports[`test adding an only child to parent 1`] = `\nImmutable.OrderedMap {\n  \"A\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"X\",\n  },\n  \"X\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"C\",\n    ],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": \"B\",\n  },\n  \"B\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"X\",\n    \"nextSibling\": null,\n  },\n  \"C\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": null,\n  },\n}\n`;\n\nexports[`test creating a new parent 1 1`] = `\nImmutable.OrderedMap {\n  \"A\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"key0\",\n  },\n  \"key0\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"B\",\n    ],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": \"C\",\n  },\n  \"B\": Immutable.Record {\n    \"parent\": \"key0\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": null,\n  },\n  \"C\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"key0\",\n    \"nextSibling\": null,\n  },\n}\n`;\n\nexports[`test creating a new parent 2 1`] = `\nImmutable.OrderedMap {\n  \"A\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"X\",\n  },\n  \"X\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"B\",\n      \"key1\",\n    ],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": \"D\",\n  },\n  \"B\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"key1\",\n  },\n  \"key1\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"key1\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"C\",\n    ],\n    \"prevSibling\": \"B\",\n    \"nextSibling\": null,\n  },\n  \"C\": Immutable.Record {\n    \"parent\": \"key1\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": null,\n  },\n  \"D\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"text\": \"delta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"X\",\n    \"nextSibling\": null,\n  },\n}\n`;\n\nexports[`test creating a updating node to become next sibling's child 1 1`] = `\nImmutable.OrderedMap {\n  \"X\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"A\",\n      \"B\",\n      \"C\",\n    ],\n    \"prevSibling\": null,\n    \"nextSibling\": \"D\",\n  },\n  \"A\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"B\",\n  },\n  \"B\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": \"C\",\n  },\n  \"C\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"B\",\n    \"nextSibling\": null,\n  },\n  \"D\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"text\": \"delta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"X\",\n    \"nextSibling\": null,\n  },\n}\n`;\n\nexports[`test creating a updating node to become next sibling's child 2 1`] = `\nImmutable.OrderedMap {\n  \"A\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"X\",\n  },\n  \"X\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"B\",\n      \"C\",\n    ],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": \"D\",\n  },\n  \"B\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"C\",\n  },\n  \"C\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"B\",\n    \"nextSibling\": null,\n  },\n  \"D\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"text\": \"delta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"X\",\n    \"nextSibling\": null,\n  },\n}\n`;\n\nexports[`test creating a updating node to become next sibling's child 3 1`] = `\nImmutable.OrderedMap {\n  \"X\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"A\",\n      \"Y\",\n    ],\n    \"prevSibling\": null,\n    \"nextSibling\": null,\n  },\n  \"A\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"Y\",\n  },\n  \"Y\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"Y\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"B\",\n      \"C\",\n    ],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": null,\n  },\n  \"B\": Immutable.Record {\n    \"parent\": \"Y\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"C\",\n  },\n  \"C\": Immutable.Record {\n    \"parent\": \"Y\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"B\",\n    \"nextSibling\": null,\n  },\n}\n`;\n\nexports[`test creating a updating node to become previous sibling's child 1 1`] = `\nImmutable.OrderedMap {\n  \"A\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"X\",\n  },\n  \"X\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"B\",\n      \"C\",\n      \"D\",\n    ],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": null,\n  },\n  \"B\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"C\",\n  },\n  \"C\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"B\",\n    \"nextSibling\": \"D\",\n  },\n  \"D\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"text\": \"delta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"C\",\n    \"nextSibling\": null,\n  },\n}\n`;\n\nexports[`test creating a updating node to become previous sibling's child 2 1`] = `\nImmutable.OrderedMap {\n  \"A\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"X\",\n  },\n  \"X\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"B\",\n      \"C\",\n    ],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": \"D\",\n  },\n  \"B\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"C\",\n  },\n  \"C\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"B\",\n    \"nextSibling\": null,\n  },\n  \"D\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"text\": \"delta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"X\",\n    \"nextSibling\": null,\n  },\n}\n`;\n\nexports[`test merging blocks 1`] = `\nImmutable.OrderedMap {\n  \"A\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"X\",\n  },\n  \"X\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"B\",\n      \"C\",\n      \"D\",\n      \"E\",\n    ],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": null,\n  },\n  \"B\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"C\",\n  },\n  \"C\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"B\",\n    \"nextSibling\": \"D\",\n  },\n  \"D\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"text\": \"delta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"C\",\n    \"nextSibling\": \"E\",\n  },\n  \"E\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"text\": \"epsilon\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"D\",\n    \"nextSibling\": null,\n  },\n}\n`;\n\nexports[`test moving child up with no parent - no-op 1`] = `\nImmutable.OrderedMap {\n  \"A\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"B\",\n  },\n  \"B\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": \"C\",\n  },\n  \"C\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"B\",\n    \"nextSibling\": null,\n  },\n}\n`;\n\nexports[`test moving first child up 1 1`] = `\nImmutable.OrderedMap {\n  \"A\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"B\",\n  },\n  \"B\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": \"X\",\n  },\n  \"X\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"C\",\n    ],\n    \"prevSibling\": \"B\",\n    \"nextSibling\": \"D\",\n  },\n  \"C\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": null,\n  },\n  \"D\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"text\": \"delta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"X\",\n    \"nextSibling\": null,\n  },\n}\n`;\n\nexports[`test moving first child up 2 1`] = `\nImmutable.OrderedMap {\n  \"X\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"A\",\n      \"B\",\n      \"Y\",\n    ],\n    \"prevSibling\": null,\n    \"nextSibling\": null,\n  },\n  \"A\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"B\",\n  },\n  \"B\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": \"Y\",\n  },\n  \"Y\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"Y\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"C\",\n    ],\n    \"prevSibling\": \"B\",\n    \"nextSibling\": null,\n  },\n  \"C\": Immutable.Record {\n    \"parent\": \"Y\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": null,\n  },\n}\n`;\n\nexports[`test moving last child up 1 1`] = `\nImmutable.OrderedMap {\n  \"A\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"X\",\n  },\n  \"X\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"B\",\n    ],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": \"C\",\n  },\n  \"B\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": null,\n  },\n  \"C\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"X\",\n    \"nextSibling\": \"D\",\n  },\n  \"D\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"text\": \"delta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"C\",\n    \"nextSibling\": null,\n  },\n}\n`;\n\nexports[`test moving last child up 2 1`] = `\nImmutable.OrderedMap {\n  \"X\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"A\",\n      \"Y\",\n      \"C\",\n    ],\n    \"prevSibling\": null,\n    \"nextSibling\": null,\n  },\n  \"A\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"Y\",\n  },\n  \"Y\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"Y\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"B\",\n    ],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": \"C\",\n  },\n  \"B\": Immutable.Record {\n    \"parent\": \"Y\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": null,\n  },\n  \"C\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"Y\",\n    \"nextSibling\": null,\n  },\n}\n`;\n\nexports[`test moving only child up deletes parent 1 1`] = `\nImmutable.OrderedMap {\n  \"A\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"B\",\n  },\n  \"B\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": \"C\",\n  },\n  \"C\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"B\",\n    \"nextSibling\": null,\n  },\n}\n`;\n\nexports[`test moving only child up deletes parent 2 1`] = `\nImmutable.OrderedMap {\n  \"B\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"C\",\n  },\n  \"C\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"B\",\n    \"nextSibling\": null,\n  },\n}\n`;\n\nexports[`test moving only child up deletes parent 3 1`] = `\nImmutable.OrderedMap {\n  \"A\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"B\",\n  },\n  \"B\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": null,\n  },\n}\n`;\n\nexports[`test moving only child up deletes parent 4 1`] = `\nImmutable.OrderedMap {\n  \"A\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"X\",\n  },\n  \"X\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"B\",\n      \"C\",\n    ],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": null,\n  },\n  \"B\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"C\",\n  },\n  \"C\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"B\",\n    \"nextSibling\": null,\n  },\n}\n`;\n\nexports[`test replacing a parent's child 1`] = `\nImmutable.OrderedMap {\n  \"A\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"text\": \"alpha\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"X\",\n  },\n  \"X\": Immutable.Record {\n    \"parent\": null,\n    \"characterList\": Immutable.List [],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [\n      \"B\",\n      \"D\",\n    ],\n    \"prevSibling\": \"A\",\n    \"nextSibling\": \"C\",\n  },\n  \"B\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"text\": \"beta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": null,\n    \"nextSibling\": \"D\",\n  },\n  \"C\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"text\": \"charlie\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"X\",\n    \"nextSibling\": null,\n  },\n  \"D\": Immutable.Record {\n    \"parent\": \"X\",\n    \"characterList\": Immutable.List [\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n      Immutable.Record {\n        \"style\": Immutable.OrderedSet [],\n        \"entity\": null,\n      },\n    ],\n    \"data\": Immutable.Map {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"text\": \"delta\",\n    \"type\": \"unstyled\",\n    \"children\": Immutable.List [],\n    \"prevSibling\": \"B\",\n    \"nextSibling\": null,\n  },\n}\n`;\n"
  },
  {
    "path": "src/model/modifier/exploration/__tests__/__snapshots__/NestedRichTextEditorUtil-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`onBackspace at start of nested block unnests it 1 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"X\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"alpha\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 1,\n    \"key\": \"B\",\n    \"nextSibling\": null,\n    \"parent\": \"X\",\n    \"prevSibling\": null,\n    \"text\": \"beta\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"X\",\n    \"text\": \"\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"X\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"B\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"nextSibling\": \"C\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"unordered-list-item\",\n  },\n}\n`;\n\nexports[`onBackspace at start of nested block unnests it 2 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"X\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"alpha\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 1,\n    \"key\": \"B\",\n    \"nextSibling\": \"Y\",\n    \"parent\": \"X\",\n    \"prevSibling\": null,\n    \"text\": \"beta\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 2,\n    \"key\": \"C\",\n    \"nextSibling\": null,\n    \"parent\": \"Y\",\n    \"prevSibling\": null,\n    \"text\": \"charlie\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 1,\n    \"key\": \"D\",\n    \"nextSibling\": null,\n    \"parent\": \"X\",\n    \"prevSibling\": \"Y\",\n    \"text\": \"\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"X\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"B\",\n      \"Y\",\n      \"D\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"Y\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n    ],\n    \"data\": Object {},\n    \"depth\": 1,\n    \"key\": \"Y\",\n    \"nextSibling\": \"D\",\n    \"parent\": \"X\",\n    \"prevSibling\": \"B\",\n    \"text\": \"\",\n    \"type\": \"unordered-list-item\",\n  },\n}\n`;\n\nexports[`onBackspace does not handle non-collapsed selections 1`] = `null`;\n\nexports[`onBackspace does not handle non-zero-offset selections 1`] = `null`;\n\nexports[`onBackspace removes a preceding atomic block 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"blockquote\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"blockquote\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"header-two\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Elephant\",\n    \"type\": \"unstyled\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"code-block\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"I\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \"last\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`onBackspace resets the current block type if empty 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"blockquote\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"blockquote\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"header-two\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Elephant\",\n    \"type\": \"unstyled\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"unstyled\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"H\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": \"I\",\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"H\",\n    \"text\": \"last\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`onDelete does not handle non-block-end or non-collapsed selections 1`] = `true`;\n\nexports[`onDelete does not handle non-block-end or non-collapsed selections 2`] = `true`;\n\nexports[`onDelete is a no-op if its at the end of the blockMap 1`] = `null`;\n\nexports[`onDelete is a no-op the end of a leaf 1`] = `null`;\n\nexports[`onDelete removes a following atomic block 1`] = `false`;\n\nexports[`onDelete removes a following atomic block 2`] = `true`;\n\nexports[`onTab (untab) merges adjacent non-leaf blocks 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"alpha\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"Y\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"beta\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"D\",\n    \"parent\": \"Y\",\n    \"prevSibling\": null,\n    \"text\": \"charlie\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"Y\",\n    \"prevSibling\": \"C\",\n    \"text\": \"delta\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"Y\",\n    \"prevSibling\": \"D\",\n    \"text\": \"epsilon\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"Y\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"Y\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n}\n`;\n\nexports[`onTab (untab) on a block with no parent does nothing 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Item 1\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"C\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"Item 2\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n      \"F\",\n      \"I\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"J\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Item 2a\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Item 2b\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"G\",\n      \"H\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": \"I\",\n    \"parent\": \"C\",\n    \"prevSibling\": \"E\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"H\",\n    \"parent\": \"F\",\n    \"prevSibling\": null,\n    \"text\": \"Item 2b i\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": null,\n    \"parent\": \"F\",\n    \"prevSibling\": \"G\",\n    \"text\": \"Item 2b ii\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"F\",\n    \"text\": \"Item 2c\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"J\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"J\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"C\",\n    \"text\": \"Item 3\",\n    \"type\": \"ordered-list-item\",\n  },\n}\n`;\n\nexports[`onTab (untab) on a first child moves block as previous sibling of parent 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Item 1\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"D\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"Item 2\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"E\",\n      \"F\",\n      \"I\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"J\",\n    \"parent\": null,\n    \"prevSibling\": \"D\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"C\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Item 2a\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Item 2b\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"G\",\n      \"H\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": \"I\",\n    \"parent\": \"C\",\n    \"prevSibling\": \"E\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"H\",\n    \"parent\": \"F\",\n    \"prevSibling\": null,\n    \"text\": \"Item 2b i\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": null,\n    \"parent\": \"F\",\n    \"prevSibling\": \"G\",\n    \"text\": \"Item 2b ii\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"F\",\n    \"text\": \"Item 2c\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"J\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"J\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"C\",\n    \"text\": \"Item 3\",\n    \"type\": \"ordered-list-item\",\n  },\n}\n`;\n\nexports[`onTab (untab) on a last child moves block as next sibling of parent 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Item 1\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"C\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"Item 2\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n      \"F\",\n      \"H\",\n      \"I\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"J\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Item 2a\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Item 2b\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"G\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": \"H\",\n    \"parent\": \"C\",\n    \"prevSibling\": \"E\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": null,\n    \"parent\": \"F\",\n    \"prevSibling\": null,\n    \"text\": \"Item 2b i\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": \"I\",\n    \"parent\": \"C\",\n    \"prevSibling\": \"F\",\n    \"text\": \"Item 2b ii\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"H\",\n    \"text\": \"Item 2c\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"J\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"J\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"C\",\n    \"text\": \"Item 3\",\n    \"type\": \"ordered-list-item\",\n  },\n}\n`;\n\nexports[`onTab (untab) on a middle child splits the block at that child 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"X\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"alpha\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"C\",\n    \"parent\": \"X\",\n    \"prevSibling\": null,\n    \"text\": \"beta\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"D\",\n    \"parent\": \"X\",\n    \"prevSibling\": \"B\",\n    \"text\": \"charlie\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": null,\n    \"parent\": \"X\",\n    \"prevSibling\": \"C\",\n    \"text\": \"delta\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": \"key1\",\n    \"parent\": null,\n    \"prevSibling\": \"X\",\n    \"text\": \"epsilon\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"key1\",\n    \"prevSibling\": null,\n    \"text\": \"foo\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key1\",\n    \"text\": \"gamma\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"X\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"B\",\n      \"C\",\n      \"D\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"nextSibling\": \"E\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"key1\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key1\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"E\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n}\n`;\n\nexports[`onTab (untab) unnests non-leaf next sibling 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"alpha\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"Y\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"beta\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": null,\n    \"parent\": \"Y\",\n    \"prevSibling\": null,\n    \"text\": \"charlie\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"Y\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"Y\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n}\n`;\n\nexports[`onTab when both siblings are non-leaf merges blocks 1 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"X\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"alpha\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"C\",\n    \"parent\": \"X\",\n    \"prevSibling\": null,\n    \"text\": \"beta\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 1,\n    \"key\": \"C\",\n    \"nextSibling\": \"D\",\n    \"parent\": \"X\",\n    \"prevSibling\": \"B\",\n    \"text\": \"charlie\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"X\",\n    \"prevSibling\": \"C\",\n    \"text\": \"delta\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"X\",\n    \"prevSibling\": \"D\",\n    \"text\": \"epsilon\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"X\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"B\",\n      \"C\",\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n}\n`;\n\nexports[`onTab when both siblings are non-leaf merges blocks 2 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"X\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"alpha\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"Y\",\n    \"parent\": \"X\",\n    \"prevSibling\": null,\n    \"text\": \"beta\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": null,\n    \"parent\": \"Y\",\n    \"prevSibling\": null,\n    \"text\": \"charlie\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 1,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"X\",\n    \"prevSibling\": \"Y\",\n    \"text\": \"delta\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"X\",\n    \"prevSibling\": \"D\",\n    \"text\": \"epsilon\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"X\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"B\",\n      \"Y\",\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"X\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"Y\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"Y\",\n    \"nextSibling\": \"D\",\n    \"parent\": \"X\",\n    \"prevSibling\": \"B\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n}\n`;\n\nexports[`onTab when siblings are at the same depth creates a new parent 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Item 1\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"C\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"Item 2\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n      \"F\",\n      \"I\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"J\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Item 2a\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Item 2b\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"G\",\n      \"key0\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": \"I\",\n    \"parent\": \"C\",\n    \"prevSibling\": \"E\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"key0\",\n    \"parent\": \"F\",\n    \"prevSibling\": null,\n    \"text\": \"Item 2b i\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 1,\n    \"key\": \"H\",\n    \"nextSibling\": null,\n    \"parent\": \"key0\",\n    \"prevSibling\": null,\n    \"text\": \"Item 2b ii\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"F\",\n    \"text\": \"Item 2c\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"J\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"J\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"C\",\n    \"text\": \"Item 3\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"key0\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"H\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"nextSibling\": null,\n    \"parent\": \"F\",\n    \"prevSibling\": \"G\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n}\n`;\n\nexports[`onTab with leaf as previous block & non-leaf as next block merges to the next block 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Item 1\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"C\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"Item 2\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"F\",\n      \"I\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"J\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Item 2a\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 1,\n    \"key\": \"E\",\n    \"nextSibling\": \"G\",\n    \"parent\": \"F\",\n    \"prevSibling\": null,\n    \"text\": \"Item 2b\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"E\",\n      \"G\",\n      \"H\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": \"I\",\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"H\",\n    \"parent\": \"F\",\n    \"prevSibling\": \"E\",\n    \"text\": \"Item 2b i\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": null,\n    \"parent\": \"F\",\n    \"prevSibling\": \"G\",\n    \"text\": \"Item 2b ii\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"F\",\n    \"text\": \"Item 2c\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"J\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"J\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"C\",\n    \"text\": \"Item 3\",\n    \"type\": \"ordered-list-item\",\n  },\n}\n`;\n\nexports[`onTab with no previous block does nothing 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Item 1\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"C\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"Item 2\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n      \"F\",\n      \"I\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"J\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Item 2a\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Item 2b\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"G\",\n      \"H\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": \"I\",\n    \"parent\": \"C\",\n    \"prevSibling\": \"E\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"H\",\n    \"parent\": \"F\",\n    \"prevSibling\": null,\n    \"text\": \"Item 2b i\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": null,\n    \"parent\": \"F\",\n    \"prevSibling\": \"G\",\n    \"text\": \"Item 2b ii\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"F\",\n    \"text\": \"Item 2c\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"J\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"J\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"C\",\n    \"text\": \"Item 3\",\n    \"type\": \"ordered-list-item\",\n  },\n}\n`;\n\nexports[`onTab with non-leaf as previous block merges to the previous block 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Item 1\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"C\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"Item 2\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"J\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Item 2a\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Item 2b\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"G\",\n      \"H\",\n      \"I\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"E\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"H\",\n    \"parent\": \"F\",\n    \"prevSibling\": null,\n    \"text\": \"Item 2b i\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": \"I\",\n    \"parent\": \"F\",\n    \"prevSibling\": \"G\",\n    \"text\": \"Item 2b ii\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 1,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": \"F\",\n    \"prevSibling\": \"H\",\n    \"text\": \"Item 2c\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"J\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"J\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"C\",\n    \"text\": \"Item 3\",\n    \"type\": \"ordered-list-item\",\n  },\n}\n`;\n\nexports[`toggleBlockType does not allow block type change for block that has children to unsupported type 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"blockquote\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"blockquote\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"header-two\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Elephant\",\n    \"type\": \"unstyled\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"code-block\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"H\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": \"I\",\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"H\",\n    \"text\": \"last\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`toggleBlockType does not allow block type change for multi block selection to unsupported type 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"blockquote\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"blockquote\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"header-two\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Elephant\",\n    \"type\": \"unstyled\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"code-block\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"H\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": \"I\",\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"H\",\n    \"text\": \"last\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`toggleBlockType does not handle nesting enabled blocks with same blockType 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"blockquote\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"header-two\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Elephant\",\n    \"type\": \"unstyled\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"code-block\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"H\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": \"I\",\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"H\",\n    \"text\": \"last\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`toggleBlockType does not handle nesting for block that has children 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"blockquote\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"header-one\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"header-two\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Elephant\",\n    \"type\": \"unstyled\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"code-block\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"H\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": \"I\",\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"H\",\n    \"text\": \"last\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`toggleBlockType does not handle nesting for blockType: \"atomic\" 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"blockquote\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"blockquote\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"header-two\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Elephant\",\n    \"type\": \"unstyled\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"code-block\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"H\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": \"I\",\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"H\",\n    \"text\": \"last\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`toggleBlockType does not handle nesting for blockType: \"code-block\" 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"blockquote\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"blockquote\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"header-two\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Elephant\",\n    \"type\": \"unstyled\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"header-two\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"H\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": \"I\",\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"H\",\n    \"text\": \"last\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`toggleBlockType does not handle nesting for multi block selection 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"blockquote\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"blockquote\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"header-one\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Elephant\",\n    \"type\": \"header-one\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"code-block\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"H\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": \"I\",\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"H\",\n    \"text\": \"last\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`toggleBlockType does not handle nesting when selection is collapsed 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"header-one\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"blockquote\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"header-two\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Elephant\",\n    \"type\": \"unstyled\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"code-block\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": \"H\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"ordered-list-item\",\n  },\n  \"H\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": \"I\",\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \" \",\n    \"type\": \"atomic\",\n  },\n  \"I\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"I\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"H\",\n    \"text\": \"last\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n"
  },
  {
    "path": "src/model/modifier/getCharacterRemovalRange.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type {DraftRemovalDirection} from 'DraftRemovalDirection';\nimport type {EntityMap} from 'EntityMap';\nimport type SelectionState from 'SelectionState';\n\nconst DraftEntitySegments = require('DraftEntitySegments');\n\nconst getRangesForDraftEntity = require('getRangesForDraftEntity');\nconst invariant = require('invariant');\n\n/**\n * Given a SelectionState and a removal direction, determine the entire range\n * that should be removed from a ContentState. This is based on any entities\n * within the target, with their `mutability` values taken into account.\n *\n * For instance, if we are attempting to remove part of an \"immutable\" entity\n * range, the entire entity must be removed. The returned `SelectionState`\n * will be adjusted accordingly.\n */\nfunction getCharacterRemovalRange(\n  entityMap: EntityMap,\n  startBlock: BlockNodeRecord,\n  endBlock: BlockNodeRecord,\n  selectionState: SelectionState,\n  direction: DraftRemovalDirection,\n): SelectionState {\n  const start = selectionState.getStartOffset();\n  const end = selectionState.getEndOffset();\n  const startEntityKey = startBlock.getEntityAt(start);\n  const endEntityKey = endBlock.getEntityAt(end - 1);\n  if (!startEntityKey && !endEntityKey) {\n    return selectionState;\n  }\n  let newSelectionState = selectionState;\n  if (startEntityKey && startEntityKey === endEntityKey) {\n    newSelectionState = getEntityRemovalRange(\n      entityMap,\n      startBlock,\n      newSelectionState,\n      direction,\n      startEntityKey,\n      true,\n      true,\n    );\n  } else if (startEntityKey && endEntityKey) {\n    const startSelectionState = getEntityRemovalRange(\n      entityMap,\n      startBlock,\n      newSelectionState,\n      direction,\n      startEntityKey,\n      false,\n      true,\n    );\n    const endSelectionState = getEntityRemovalRange(\n      entityMap,\n      endBlock,\n      newSelectionState,\n      direction,\n      endEntityKey,\n      false,\n      false,\n    );\n    newSelectionState = newSelectionState.merge({\n      anchorOffset: startSelectionState.getAnchorOffset(),\n      focusOffset: endSelectionState.getFocusOffset(),\n      isBackward: false,\n    });\n  } else if (startEntityKey) {\n    const startSelectionState = getEntityRemovalRange(\n      entityMap,\n      startBlock,\n      newSelectionState,\n      direction,\n      startEntityKey,\n      false,\n      true,\n    );\n    newSelectionState = newSelectionState.merge({\n      anchorOffset: startSelectionState.getStartOffset(),\n      isBackward: false,\n    });\n  } else if (endEntityKey) {\n    const endSelectionState = getEntityRemovalRange(\n      entityMap,\n      endBlock,\n      newSelectionState,\n      direction,\n      endEntityKey,\n      false,\n      false,\n    );\n    newSelectionState = newSelectionState.merge({\n      focusOffset: endSelectionState.getEndOffset(),\n      isBackward: false,\n    });\n  }\n  return newSelectionState;\n}\n\nfunction getEntityRemovalRange(\n  entityMap: EntityMap,\n  block: BlockNodeRecord,\n  selectionState: SelectionState,\n  direction: DraftRemovalDirection,\n  entityKey: string,\n  isEntireSelectionWithinEntity: boolean,\n  isEntityAtStart: boolean,\n): SelectionState {\n  let start = selectionState.getStartOffset();\n  let end = selectionState.getEndOffset();\n  const entity = entityMap.get(entityKey);\n  const mutability = entity.getMutability();\n  const sideToConsider = isEntityAtStart ? start : end;\n\n  // `MUTABLE` entities can just have the specified range of text removed\n  // directly. No adjustments are needed.\n  if (mutability === 'MUTABLE') {\n    return selectionState;\n  }\n\n  // Find the entity range that overlaps with our removal range.\n  const entityRanges = getRangesForDraftEntity(block, entityKey).filter(\n    range => sideToConsider <= range.end && sideToConsider >= range.start,\n  );\n\n  invariant(\n    entityRanges.length == 1,\n    'There should only be one entity range within this removal range.',\n  );\n\n  const entityRange = entityRanges[0];\n\n  // For `IMMUTABLE` entity types, we will remove the entire entity range.\n  if (mutability === 'IMMUTABLE') {\n    return selectionState.merge({\n      anchorOffset: entityRange.start,\n      focusOffset: entityRange.end,\n      isBackward: false,\n    });\n  }\n\n  // For `SEGMENTED` entity types, determine the appropriate segment to\n  // remove.\n  if (!isEntireSelectionWithinEntity) {\n    if (isEntityAtStart) {\n      end = entityRange.end;\n    } else {\n      start = entityRange.start;\n    }\n  }\n\n  const removalRange = DraftEntitySegments.getRemovalRange(\n    start,\n    end,\n    block.getText().slice(entityRange.start, entityRange.end),\n    entityRange.start,\n    direction,\n  );\n\n  return selectionState.merge({\n    anchorOffset: removalRange.start,\n    focusOffset: removalRange.end,\n    isBackward: false,\n  });\n}\n\nmodule.exports = getCharacterRemovalRange;\n"
  },
  {
    "path": "src/model/modifier/getRangesForDraftEntity.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type {DraftRange} from 'DraftRange';\n\nconst invariant = require('invariant');\n\n/**\n * Obtain the start and end positions of the range that has the\n * specified entity applied to it.\n *\n * Entity keys are applied only to contiguous stretches of text, so this\n * method searches for the first instance of the entity key and returns\n * the subsequent range.\n */\nfunction getRangesForDraftEntity(\n  block: BlockNodeRecord,\n  key: string,\n): Array<DraftRange> {\n  const ranges = [];\n  block.findEntityRanges(\n    c => c.getEntity() === key,\n    (start, end) => {\n      ranges.push({start, end});\n    },\n  );\n\n  invariant(!!ranges.length, 'Entity key not found in this range.');\n\n  return ranges;\n}\n\nmodule.exports = getRangesForDraftEntity;\n"
  },
  {
    "path": "src/model/paste/DraftPasteProcessor.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type CharacterMetadata from 'CharacterMetadata';\nimport type {DraftBlockRenderMap} from 'DraftBlockRenderMap';\nimport type {DraftBlockType} from 'DraftBlockType';\nimport type {EntityMap} from 'EntityMap';\n\nconst ContentBlock = require('ContentBlock');\nconst ContentBlockNode = require('ContentBlockNode');\n\nconst convertFromHTMLToContentBlocks = require('convertFromHTMLToContentBlocks');\nconst generateRandomKey = require('generateRandomKey');\nconst getSafeBodyFromHTML = require('getSafeBodyFromHTML');\nconst gkx = require('gkx');\nconst Immutable = require('immutable');\nconst sanitizeDraftText = require('sanitizeDraftText');\n\nconst {List, Repeat} = Immutable;\n\nconst experimentalTreeDataSupport = gkx('draft_tree_data_support');\nconst ContentBlockRecord = experimentalTreeDataSupport\n  ? ContentBlockNode\n  : ContentBlock;\n\nconst DraftPasteProcessor = {\n  processHTML(\n    html: string,\n    blockRenderMap?: DraftBlockRenderMap,\n  ): ?{\n    contentBlocks: ?Array<BlockNodeRecord>,\n    entityMap: EntityMap,\n    ...\n  } {\n    return convertFromHTMLToContentBlocks(\n      html,\n      getSafeBodyFromHTML,\n      blockRenderMap,\n    );\n  },\n\n  processText(\n    textBlocks: Array<string>,\n    character: CharacterMetadata,\n    type: DraftBlockType,\n  ): Array<BlockNodeRecord> {\n    return textBlocks.reduce((acc, textLine, index) => {\n      textLine = sanitizeDraftText(textLine);\n      const key = generateRandomKey();\n\n      let blockNodeConfig = {\n        key,\n        type,\n        text: textLine,\n        characterList: List(Repeat(character, textLine.length)),\n      };\n\n      // next block updates previous block\n      if (experimentalTreeDataSupport && index !== 0) {\n        const prevSiblingIndex = index - 1;\n        // update previous block\n        const previousBlock = (acc[prevSiblingIndex] = acc[\n          prevSiblingIndex\n        ].merge({\n          nextSibling: key,\n        }));\n        blockNodeConfig = {\n          ...blockNodeConfig,\n          prevSibling: previousBlock.getKey(),\n        };\n      }\n\n      acc.push(new ContentBlockRecord(blockNodeConfig));\n\n      return acc;\n    }, []);\n  },\n};\n\nmodule.exports = DraftPasteProcessor;\n"
  },
  {
    "path": "src/model/paste/__mocks__/getSafeBodyFromHTML.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @format\n * @oncall draft_js\n */\n\n// THIS IS PURELY A MOCK TO GET AROUND THE TEST FRAMEWORK\n// Never use this for anything else ever.\nfunction getUnsafeBodyFromHTML(html) {\n  const fragment = document.createElement('body');\n  const match = html.match(/<body>(.*?)<\\/body>/);\n  fragment.innerHTML = match ? match[1] : html;\n  return fragment;\n}\n\nmodule.exports = getUnsafeBodyFromHTML;\n"
  },
  {
    "path": "src/model/paste/__tests__/DraftPasteProcessor-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\njest.mock('generateRandomKey');\n\nconst DraftPasteProcessor = require('DraftPasteProcessor');\n\nconst Immutable = require('immutable');\nconst mockUUID = require('mockUUID');\n\nconst {OrderedSet, Map} = Immutable;\n\nconst CUSTOM_BLOCK_MAP = Map({\n  'header-one': {\n    element: 'h1',\n  },\n  'header-two': {\n    element: 'h2',\n  },\n  'header-three': {\n    element: 'h3',\n  },\n  'unordered-list-item': {\n    element: 'li',\n  },\n  'ordered-list-item': {\n    element: 'li',\n  },\n  blockquote: {\n    element: 'blockquote',\n  },\n  'code-block': {\n    element: 'pre',\n  },\n  paragraph: {\n    element: 'p',\n  },\n  unstyled: {\n    element: 'div',\n  },\n});\n\nconst EMPTY_CHAR_METADATA = OrderedSet();\n\nconst toggleExperimentalTreeDataSupport = enabled => {\n  jest.doMock('gkx', () => name => {\n    return name === 'draft_tree_data_support' ? enabled : false;\n  });\n};\n\nconst assertDraftPasteProcessorProcessText = (\n  textBlocks,\n  experimentalTreeDataSupport = false,\n) => {\n  toggleExperimentalTreeDataSupport(experimentalTreeDataSupport);\n  const contentBlocks = DraftPasteProcessor.processText(\n    textBlocks,\n    EMPTY_CHAR_METADATA,\n    'unstyled',\n  );\n  expect(contentBlocks.map(block => block.toJS())).toMatchSnapshot();\n};\n\nconst assertDraftPasteProcessorProcessHTML = (\n  html,\n  blockMap = CUSTOM_BLOCK_MAP,\n  experimentalTreeDataSupport = false,\n) => {\n  toggleExperimentalTreeDataSupport(experimentalTreeDataSupport);\n  const {contentBlocks} = DraftPasteProcessor.processHTML(html, blockMap);\n  expect(contentBlocks.map(block => block.toJS())).toMatchSnapshot();\n};\n\nbeforeEach(() => {\n  jest.resetModules();\n  jest.mock('uuid', () => mockUUID);\n});\n\ntest('must identify italics text', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    <i>hello</i> hi\n  `);\n});\n\ntest('must identify overlapping inline styles', () => {\n  /* eslint-disable fb-www/gender-neutral-language */\n  assertDraftPasteProcessorProcessHTML(`\n    <i>\n      <b>he</b>\n      hi\n    </i>\n  `);\n  /* eslint-enable fb-www/gender-neutral-language */\n});\n\ntest('must identify block styles', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    <ol>\n      <li>hi</li>\n      <li>there</li>\n    </ol>\n  `);\n});\n\ntest('must collapse nested blocks to the topmost level', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    <ul>\n      <li>\n        <h2>what</h2>\n      </li>\n    </ul>\n  `);\n});\n\n/**\n * todo: azelenskiy\n * Changes to the mocked DOM appear to have broken this.\n *\n * test('must suppress blocks nested inside other blocks', () => {\n *   const html = '<p><h2>Some text here</h2> more text here </p>';\n *   const output = DraftPasteProcessor.processHTML(html, CUSTOM_BLOCK_MAP);\n *   assertBlockTypes(output, [\n *   'unstyled',\n *   ]);\n * });\n */\n\ntest('must detect two touching blocks', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    <h1>hi</h1>\n    <h2>hi</h2>\n  `);\n});\n\ntest('must insert a block when needed', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    <h1> hi </h1>\n    <h1> </h1>\n    <span> whatever </span>\n    <h2>hi </h2>\n  `);\n});\n\ntest('must not generate fake blocks on heavy nesting', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    <p>\n      <span>\n        <span>\n          <span>Word</span>\n        </span>\n      </span>\n      <span>\n        <span>,</span>\n      </span>\n    </p>\n  `);\n});\n\ntest('must preserve spaces', () => {\n  assertDraftPasteProcessorProcessHTML(`<span>hello</span> <span>hi</span>`);\n  assertDraftPasteProcessorProcessHTML(`<span>hello </span><span>hi</span>`);\n  assertDraftPasteProcessorProcessHTML(`<span>hello</span><span> hi</span>`);\n});\n\ntest('must treat divs as Ps when we do not have semantic markup', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    <div>hi</div>\n    <div>hello</div>\n  `);\n});\n\ntest('must NOT treat divs as Ps when we pave Ps', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    <div>\n      <p>hi</p>\n      <p>hello</p>\n    </div>\n  `);\n});\n\ntest('must replace br tags with soft newlines', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    hi<br>hello\n  `);\n});\n\ntest('must strip xml carriages and zero width spaces', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    hi&#13;&#8203;hello\n  `);\n});\n\ntest('must split unstyled blocks on two br tags', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    hi<br><br>hello\n  `);\n});\n\ntest('must NOT split unstyled blocks inside a styled block', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    <pre>\n      hi<br><br>hello\n    </pre>\n  `);\n});\n\ntest('must replace newlines in regular tags', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    <div>\n      hello\\nthere\n    </div>\n  `);\n});\n\ntest('must preserve newlines in pre tags', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    <pre>\n      hello\\nthere\n    </pre>\n  `);\n});\n\ntest('must preserve newlines in whitespace in pre tags', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    <pre>\n      <span>hello</span>\\n<span>there</span>\n    </pre>\n  `);\n});\n\ntest('must parse based on style attribute', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    <span style=\"font-weight: bold;\">\n      Bold <span style=\"font-style: italic;\">Italic </span>\n    </span>.\n  `);\n});\n\ntest('must detect links in pasted content', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    This is a <a href=\"http://www.facebook.com\">link</a>, yep.\n  `);\n});\n\ntest('must preserve styles inside links in a good way', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    A <a href=\"http://www.facebook.com\"><i>cool</i> link</a>, yep.\n  `);\n});\n\ntest('must ignore links that do not actually link anywhere', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    This is a <a>link</a>, yep.\n  `);\n});\n\ntest('must ignore javascript: links', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    This is a <a href=\"javascript:void(0)\">link</a>, yep.\n  `);\n});\n\ntest('must preserve mailto: links', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    This is a <a href=\"mailto:example@example.com\">link</a>, yep.\n  `);\n});\n\ntest('Tolerate doule BR tags separated by whitespace', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    hi<br>  <br>hello\n  `);\n});\n\ntest('Strip whitespace after block dividers', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    <p>hello</p> <p> what</p>\n  `);\n});\n\ntest('Should detect when somthing is un-styled in a child', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    <b>\n      hello<span style=\"font-weight:400;\">there</span>\n    </b>\n  `);\n\n  assertDraftPasteProcessorProcessHTML(`\n    <i>\n      hello<span style=\"font-style:normal;\">there</span>\n    </i>\n  `);\n\n  // nothing to remove. make sure we don't throw an error\n  assertDraftPasteProcessorProcessHTML(`\n    <span>hello<span style=\"font-style:normal;\">there</span></span>\n  `);\n});\n\ntest('must preserve list formatting', () => {\n  assertDraftPasteProcessorProcessHTML(`\n    what\n    <ul>\n      <li>what</li>\n      <li>\n        what\n        <ol>\n          <li>one</li>\n          <li>two</li>\n        </ol>\n      </li>\n      <li>what</li>\n    </ul>\n  `);\n});\n\ntest('must create nested elements when experimentalTreeDataSupport is enabled', () => {\n  assertDraftPasteProcessorProcessHTML(\n    `\n    <blockquote>\n      <h2>Heading inside blockquote</h2>\n      <p><em>some</em> <strong>text</strong></p>\n    </blockquote>\n  `,\n    CUSTOM_BLOCK_MAP,\n    true,\n  );\n});\n\ntest('must create ContentBlocks when experimentalTreeDataSupport is disabled while processing text', () => {\n  assertDraftPasteProcessorProcessText(['Alpha', 'Beta', 'Charlie']);\n});\n\ntest('must create ContentBlockNodes when experimentalTreeDataSupport is enabled while processing text', () => {\n  assertDraftPasteProcessorProcessText(['Alpha', 'Beta', 'Charlie'], true);\n});\n"
  },
  {
    "path": "src/model/paste/__tests__/__snapshots__/DraftPasteProcessor-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`Should detect when somthing is un-styled in a child 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"hellothere\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`Should detect when somthing is un-styled in a child 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key5\",\n    \"text\": \"hellothere\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`Should detect when somthing is un-styled in a child 3`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key8\",\n    \"text\": \"hellothere\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`Strip whitespace after block dividers 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"hello\",\n    \"type\": \"paragraph\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"what\",\n    \"type\": \"paragraph\",\n  },\n]\n`;\n\nexports[`Tolerate doule BR tags separated by whitespace 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"hi\n \nhello\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must NOT split unstyled blocks inside a styled block 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"hi\n\nhello\",\n    \"type\": \"code-block\",\n  },\n]\n`;\n\nexports[`must NOT treat divs as Ps when we pave Ps 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"hi\",\n    \"type\": \"paragraph\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"hello\",\n    \"type\": \"paragraph\",\n  },\n]\n`;\n\nexports[`must collapse nested blocks to the topmost level 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"what\n\",\n    \"type\": \"unordered-list-item\",\n  },\n]\n`;\n\nexports[`must create ContentBlockNodes when experimentalTreeDataSupport is enabled while processing text 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Array [],\n      Array [],\n      Array [],\n      Array [],\n      Array [],\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"nextSibling\": \"key1\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Array [],\n      Array [],\n      Array [],\n      Array [],\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key1\",\n    \"nextSibling\": \"key2\",\n    \"parent\": null,\n    \"prevSibling\": \"key0\",\n    \"text\": \"Beta\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Array [],\n      Array [],\n      Array [],\n      Array [],\n      Array [],\n      Array [],\n      Array [],\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key1\",\n    \"text\": \"Charlie\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must create ContentBlocks when experimentalTreeDataSupport is disabled while processing text 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Array [],\n      Array [],\n      Array [],\n      Array [],\n      Array [],\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Array [],\n      Array [],\n      Array [],\n      Array [],\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key1\",\n    \"text\": \"Beta\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Array [],\n      Array [],\n      Array [],\n      Array [],\n      Array [],\n      Array [],\n      Array [],\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"Charlie\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must create nested elements when experimentalTreeDataSupport is enabled 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"key3\",\n      \"key4\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"blockquote\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"nextSibling\": \"key4\",\n    \"parent\": \"key2\",\n    \"prevSibling\": null,\n    \"text\": \"Heading inside blockquote\",\n    \"type\": \"header-two\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"nextSibling\": null,\n    \"parent\": \"key2\",\n    \"prevSibling\": \"key3\",\n    \"text\": \"some text\",\n    \"type\": \"paragraph\",\n  },\n]\n`;\n\nexports[`must detect links in pasted content 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"This is a link, yep.\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must detect two touching blocks 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"hi\",\n    \"type\": \"header-one\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"hi\",\n    \"type\": \"header-two\",\n  },\n]\n`;\n\nexports[`must identify block styles 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"hi\",\n    \"type\": \"ordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"there\",\n    \"type\": \"ordered-list-item\",\n  },\n]\n`;\n\nexports[`must identify italics text 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"hello hi\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must identify overlapping inline styles 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"he      hi\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must ignore javascript: links 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"This is a link, yep.\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must ignore links that do not actually link anywhere 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"This is a link, yep.\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must insert a block when needed 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"hi\",\n    \"type\": \"header-one\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"\",\n    \"type\": \"header-one\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"whatever\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key5\",\n    \"text\": \"hi\",\n    \"type\": \"header-two\",\n  },\n]\n`;\n\nexports[`must not generate fake blocks on heavy nesting 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"Word    ,\",\n    \"type\": \"paragraph\",\n  },\n]\n`;\n\nexports[`must parse based on style attribute 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"Bold Italic  .\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must preserve list formatting 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"what\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"what\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"whatone\ntwo\n\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key8\",\n    \"text\": \"what\",\n    \"type\": \"unordered-list-item\",\n  },\n]\n`;\n\nexports[`must preserve mailto: links 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"This is a link, yep.\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must preserve newlines in pre tags 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"hello\nthere\",\n    \"type\": \"code-block\",\n  },\n]\n`;\n\nexports[`must preserve newlines in whitespace in pre tags 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"hello\nthere\",\n    \"type\": \"code-block\",\n  },\n]\n`;\n\nexports[`must preserve spaces 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"hello hi\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must preserve spaces 2`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key5\",\n    \"text\": \"hello hi\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must preserve spaces 3`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key8\",\n    \"text\": \"hello hi\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must preserve styles inside links in a good way 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"A cool link, yep.\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must replace br tags with soft newlines 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"hi\nhello\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must replace newlines in regular tags 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"hello there\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must split unstyled blocks on two br tags 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"hi\n\nhello\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must strip xml carriages and zero width spaces 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"hihello\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must treat divs as Ps when we do not have semantic markup 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"hi\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"hello\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n"
  },
  {
    "path": "src/model/paste/getSafeBodyFromHTML.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst UserAgent = require('UserAgent');\n\nconst invariant = require('invariant');\n\nconst isOldIE = UserAgent.isBrowser('IE <= 9');\n\n// Provides a dom node that will not execute scripts\n// https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation.createHTMLDocument\n// https://developer.mozilla.org/en-US/Add-ons/Code_snippets/HTML_to_DOM\n\nfunction getSafeBodyFromHTML(html: string): ?Element {\n  let doc;\n  let root = null;\n  // Provides a safe context\n  if (\n    !isOldIE &&\n    document.implementation &&\n    // $FlowFixMe[method-unbinding] added when improving typing for this parameters\n    document.implementation.createHTMLDocument\n  ) {\n    doc = document.implementation.createHTMLDocument('foo');\n    invariant(doc.documentElement, 'Missing doc.documentElement');\n    doc.documentElement.innerHTML = html;\n    root = doc.getElementsByTagName('body')[0];\n  }\n  return root;\n}\n\nmodule.exports = getSafeBodyFromHTML;\n"
  },
  {
    "path": "src/model/transaction/ContentStateInlineStyle.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type ContentState from 'ContentState';\nimport type SelectionState from 'SelectionState';\n\nconst CharacterMetadata = require('CharacterMetadata');\n\nconst {Map} = require('immutable');\n\nconst ContentStateInlineStyle = {\n  add(\n    contentState: ContentState,\n    selectionState: SelectionState,\n    inlineStyle: string,\n  ): ContentState {\n    return modifyInlineStyle(contentState, selectionState, inlineStyle, true);\n  },\n\n  remove(\n    contentState: ContentState,\n    selectionState: SelectionState,\n    inlineStyle: string,\n  ): ContentState {\n    return modifyInlineStyle(contentState, selectionState, inlineStyle, false);\n  },\n};\n\nfunction modifyInlineStyle(\n  contentState: ContentState,\n  selectionState: SelectionState,\n  inlineStyle: string,\n  addOrRemove: boolean,\n): ContentState {\n  const blockMap = contentState.getBlockMap();\n  const startKey = selectionState.getStartKey();\n  const startOffset = selectionState.getStartOffset();\n  const endKey = selectionState.getEndKey();\n  const endOffset = selectionState.getEndOffset();\n\n  const newBlocks = blockMap\n    .skipUntil((_, k) => k === startKey)\n    .takeUntil((_, k) => k === endKey)\n    .concat(Map([[endKey, blockMap.get(endKey)]]))\n    .map((block, blockKey) => {\n      let sliceStart;\n      let sliceEnd;\n\n      if (startKey === endKey) {\n        sliceStart = startOffset;\n        sliceEnd = endOffset;\n      } else {\n        sliceStart = blockKey === startKey ? startOffset : 0;\n        sliceEnd = blockKey === endKey ? endOffset : block.getLength();\n      }\n\n      let chars = block.getCharacterList();\n      let current;\n      while (sliceStart < sliceEnd) {\n        current = chars.get(sliceStart);\n        chars = chars.set(\n          sliceStart,\n          addOrRemove\n            ? CharacterMetadata.applyStyle(current, inlineStyle)\n            : CharacterMetadata.removeStyle(current, inlineStyle),\n        );\n        sliceStart++;\n      }\n\n      return block.set('characterList', chars);\n    });\n\n  return contentState.merge({\n    blockMap: blockMap.merge(newBlocks),\n    selectionBefore: selectionState,\n    selectionAfter: selectionState,\n  });\n}\n\nmodule.exports = ContentStateInlineStyle;\n"
  },
  {
    "path": "src/model/transaction/__tests__/ContentStateInlineStyle-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\nimport type ContentState from 'ContentState';\nimport type SelectionState from 'SelectionState';\n\nconst ContentStateInlineStyle = require('ContentStateInlineStyle');\n\nconst getSampleStateForTesting = require('getSampleStateForTesting');\n\nconst {contentState, selectionState} = getSampleStateForTesting();\n\nconst initialSelection = selectionState.set(\n  'focusOffset',\n  contentState.getBlockForKey(selectionState.getStartKey()).getLength(),\n);\n\nconst assertAddContentStateInlineStyle = (\n  inlineStyle: $TEMPORARY$string<'BOLD'> | $TEMPORARY$string<'ITALIC'>,\n  selection: $FlowFixMe | SelectionState = selectionState,\n  content: ContentState = contentState,\n) => {\n  const newContentState = ContentStateInlineStyle.add(\n    content,\n    selection,\n    inlineStyle,\n  );\n\n  expect(newContentState.getBlockMap().toJS()).toMatchSnapshot();\n\n  return newContentState;\n};\n\nconst assertRemoveContentStateInlineStyle = (\n  inlineStyle: $TEMPORARY$string<'BOLD'> | $TEMPORARY$string<'ITALIC'>,\n  selection: $FlowFixMe | SelectionState = selectionState,\n  content: ContentState = contentState,\n) => {\n  const newContentState = ContentStateInlineStyle.remove(\n    content,\n    selection,\n    inlineStyle,\n  );\n\n  expect(newContentState.getBlockMap().toJS()).toMatchSnapshot();\n\n  return newContentState;\n};\n\ntest('must add styles', () => {\n  const modified = assertAddContentStateInlineStyle('BOLD', initialSelection);\n\n  assertAddContentStateInlineStyle(\n    'ITALIC',\n    selectionState.set('focusOffset', 2),\n    modified,\n  );\n});\n\ntest('must remove styles', () => {\n  // Go ahead and add some styles that we'll then remove.\n  let modified = assertAddContentStateInlineStyle('BOLD', initialSelection);\n  modified = assertAddContentStateInlineStyle(\n    'ITALIC',\n    initialSelection,\n    modified,\n  );\n\n  // we then remove the added styles\n  modified = assertRemoveContentStateInlineStyle(\n    'BOLD',\n    initialSelection,\n    modified,\n  );\n  assertRemoveContentStateInlineStyle(\n    'ITALIC',\n    initialSelection.set('focusOffset', 2),\n    modified,\n  );\n});\n\ntest('must add and remove styles accross multiple blocks', () => {\n  const nextBlock = contentState.getBlockAfter(selectionState.getStartKey());\n  const selection = selectionState.merge({\n    focusKey: nextBlock?.getKey(),\n    focusOffset: nextBlock?.getLength(),\n  });\n\n  const modified = assertAddContentStateInlineStyle('BOLD', selection);\n  assertRemoveContentStateInlineStyle('BOLD', selection, modified);\n});\n"
  },
  {
    "path": "src/model/transaction/__tests__/__snapshots__/ContentStateInlineStyle-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must add and remove styles accross multiple blocks 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must add and remove styles accross multiple blocks 2`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must add styles 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must add styles 2`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove styles 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove styles 2`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove styles 3`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove styles 4`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n"
  },
  {
    "path": "src/model/transaction/__tests__/__snapshots__/applyEntityToContentBlock-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must apply at the end 1`] = `\nObject {\n  \"characterList\": Array [\n    Object {\n      \"entity\": null,\n      \"style\": Array [],\n    },\n    Object {\n      \"entity\": null,\n      \"style\": Array [],\n    },\n    Object {\n      \"entity\": null,\n      \"style\": Array [],\n    },\n    Object {\n      \"entity\": \"x\",\n      \"style\": Array [],\n    },\n    Object {\n      \"entity\": \"x\",\n      \"style\": Array [],\n    },\n  ],\n  \"data\": Object {},\n  \"depth\": 0,\n  \"key\": \"a\",\n  \"text\": \"Hello\",\n  \"type\": \"unstyled\",\n}\n`;\n\nexports[`must apply from the start 1`] = `\nObject {\n  \"characterList\": Array [\n    Object {\n      \"entity\": \"x\",\n      \"style\": Array [],\n    },\n    Object {\n      \"entity\": \"x\",\n      \"style\": Array [],\n    },\n    Object {\n      \"entity\": null,\n      \"style\": Array [],\n    },\n    Object {\n      \"entity\": null,\n      \"style\": Array [],\n    },\n    Object {\n      \"entity\": null,\n      \"style\": Array [],\n    },\n  ],\n  \"data\": Object {},\n  \"depth\": 0,\n  \"key\": \"a\",\n  \"text\": \"Hello\",\n  \"type\": \"unstyled\",\n}\n`;\n\nexports[`must apply to the entire text 1`] = `\nObject {\n  \"characterList\": Array [\n    Object {\n      \"entity\": \"x\",\n      \"style\": Array [],\n    },\n    Object {\n      \"entity\": \"x\",\n      \"style\": Array [],\n    },\n    Object {\n      \"entity\": \"x\",\n      \"style\": Array [],\n    },\n    Object {\n      \"entity\": \"x\",\n      \"style\": Array [],\n    },\n    Object {\n      \"entity\": \"x\",\n      \"style\": Array [],\n    },\n  ],\n  \"data\": Object {},\n  \"depth\": 0,\n  \"key\": \"a\",\n  \"text\": \"Hello\",\n  \"type\": \"unstyled\",\n}\n`;\n\nexports[`must apply within 1`] = `\nObject {\n  \"characterList\": Array [\n    Object {\n      \"entity\": null,\n      \"style\": Array [],\n    },\n    Object {\n      \"entity\": \"x\",\n      \"style\": Array [],\n    },\n    Object {\n      \"entity\": \"x\",\n      \"style\": Array [],\n    },\n    Object {\n      \"entity\": \"x\",\n      \"style\": Array [],\n    },\n    Object {\n      \"entity\": null,\n      \"style\": Array [],\n    },\n  ],\n  \"data\": Object {},\n  \"depth\": 0,\n  \"key\": \"a\",\n  \"text\": \"Hello\",\n  \"type\": \"unstyled\",\n}\n`;\n"
  },
  {
    "path": "src/model/transaction/__tests__/__snapshots__/applyEntityToContentState-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must apply entity key 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"x\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"x\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"x\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"x\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"x\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must apply entity key accross multiple blocks 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"x\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"x\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"x\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"x\",\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"x\",\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"x\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"x\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"x\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"x\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"x\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must apply null entity 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must apply null entity key accross multiple blocks 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n"
  },
  {
    "path": "src/model/transaction/__tests__/__snapshots__/getContentStateFragment-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must be able to return all selected contentBlockNodes 1`] = `\nObject {\n  \"key4\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"nextSibling\": \"key5\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"key5\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"key6\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key5\",\n    \"nextSibling\": \"key7\",\n    \"parent\": null,\n    \"prevSibling\": \"key4\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  \"key6\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key6\",\n    \"nextSibling\": null,\n    \"parent\": \"key5\",\n    \"prevSibling\": null,\n    \"text\": \"Charlie\",\n    \"type\": \"unstyled\",\n  },\n  \"key7\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key7\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key5\",\n    \"text\": \"Delta\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`must be able to return all selected contentBlocks 1`] = `\nObject {\n  \"key0\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"key1\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key1\",\n    \"text\": \"Beta\",\n    \"type\": \"unstyled\",\n  },\n  \"key2\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"Charlie\",\n    \"type\": \"unstyled\",\n  },\n  \"key3\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"Delta\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`must be able to return contentBlockNodes selected within 1`] = `\nObject {\n  \"key10\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"key11\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key10\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  \"key11\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key11\",\n    \"nextSibling\": null,\n    \"parent\": \"key10\",\n    \"prevSibling\": null,\n    \"text\": \"Charlie\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`must be able to return contentBlocks selected within 1`] = `\nObject {\n  \"key8\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key8\",\n    \"text\": \"Beta\",\n    \"type\": \"unstyled\",\n  },\n  \"key9\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key9\",\n    \"text\": \"Charlie\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`must be able to return first ContentBlock selected 1`] = `\nObject {\n  \"key12\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key12\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`must be able to return first ContentBlockNode selected 1`] = `\nObject {\n  \"key13\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key13\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`must be able to return last ContentBlock selected 1`] = `\nObject {\n  \"key14\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key14\",\n    \"text\": \"Delta\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`must be able to return last ContentBlockNode selected 1`] = `\nObject {\n  \"key15\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key15\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n"
  },
  {
    "path": "src/model/transaction/__tests__/__snapshots__/insertFragmentIntoContentState-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must apply fragment at the end 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alphaxx\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must apply fragment to the start 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"xxAlpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must apply fragment to within block 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alxxpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must apply multiblock fragments 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"xx\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {\n      \"b\": 2,\n    },\n    \"depth\": 0,\n    \"key\": \"key4\",\n    \"text\": \"yyAlpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must be able to insert a fragment of ContentBlockNodes while updating the target block with the first fragment block properties 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"first\",\n    \"nextSibling\": \"key15\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"key16\",\n    ],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"key15\",\n    \"nextSibling\": \"second\",\n    \"parent\": null,\n    \"prevSibling\": \"first\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"key17\",\n    ],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"key16\",\n    \"nextSibling\": null,\n    \"parent\": \"key15\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"key17\",\n    \"nextSibling\": null,\n    \"parent\": \"key16\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"second\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key15\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must be able to insert a fragment of ContentBlockNodes while updating the target block with the first fragment block properties after nested block 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"firstChild\",\n      \"key19\",\n      \"key22\",\n      \"lastChild\",\n    ],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"root\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"firstChild\",\n    \"nextSibling\": \"key19\",\n    \"parent\": \"root\",\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"key20\",\n    ],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"key19\",\n    \"nextSibling\": \"key22\",\n    \"parent\": \"root\",\n    \"prevSibling\": \"firstChild\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"key21\",\n    ],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"key20\",\n    \"nextSibling\": null,\n    \"parent\": \"key19\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"key21\",\n    \"nextSibling\": null,\n    \"parent\": \"key20\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"key22\",\n    \"nextSibling\": \"lastChild\",\n    \"parent\": \"root\",\n    \"prevSibling\": \"key19\",\n    \"text\": \"Elephant\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"lastChild\",\n    \"nextSibling\": null,\n    \"parent\": \"root\",\n    \"prevSibling\": \"key22\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must be able to insert a fragment with a single ContentBlockNode 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"some text\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must be able to insert fragment of ContentBlockNodes 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"first\",\n    \"nextSibling\": \"key6\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"key7\",\n    ],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"key6\",\n    \"nextSibling\": \"key9\",\n    \"parent\": null,\n    \"prevSibling\": \"first\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"key8\",\n    ],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"key7\",\n    \"nextSibling\": null,\n    \"parent\": \"key6\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"key8\",\n    \"nextSibling\": null,\n    \"parent\": \"key7\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"key9\",\n    \"nextSibling\": \"second\",\n    \"parent\": null,\n    \"prevSibling\": \"key6\",\n    \"text\": \"Elephant\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"second\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key9\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must be able to insert fragment of ContentBlockNodes after nested block 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"firstChild\",\n      \"key10\",\n      \"key13\",\n      \"lastChild\",\n    ],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"root\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"firstChild\",\n    \"nextSibling\": \"key10\",\n    \"parent\": \"root\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"key11\",\n    ],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"key10\",\n    \"nextSibling\": \"key13\",\n    \"parent\": \"root\",\n    \"prevSibling\": \"firstChild\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"key12\",\n    ],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"key11\",\n    \"nextSibling\": null,\n    \"parent\": \"key10\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"key12\",\n    \"nextSibling\": null,\n    \"parent\": \"key11\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"key13\",\n    \"nextSibling\": \"lastChild\",\n    \"parent\": \"root\",\n    \"prevSibling\": \"key10\",\n    \"text\": \"Elephant\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {\n      \"a\": 1,\n    },\n    \"depth\": 0,\n    \"key\": \"lastChild\",\n    \"nextSibling\": null,\n    \"parent\": \"root\",\n    \"prevSibling\": \"key13\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n"
  },
  {
    "path": "src/model/transaction/__tests__/__snapshots__/insertIntoList-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must insert at beginning of list 1`] = `\nImmutable.List [\n  100,\n  101,\n  102,\n  0,\n  1,\n  2,\n  3,\n  4,\n]\n`;\n\nexports[`must insert at end of list 1`] = `\nImmutable.List [\n  0,\n  1,\n  2,\n  3,\n  4,\n  100,\n  101,\n  102,\n]\n`;\n\nexports[`must insert within a list 1`] = `\nImmutable.List [\n  0,\n  1,\n  2,\n  100,\n  101,\n  102,\n  3,\n  4,\n]\n`;\n"
  },
  {
    "path": "src/model/transaction/__tests__/__snapshots__/insertTextIntoContentState-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must insert at the end 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alphaxx\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must insert at the start 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"xxAlpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must insert within block 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alxxpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must return early if no text is provided 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n"
  },
  {
    "path": "src/model/transaction/__tests__/__snapshots__/moveBlockInContentState-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must be able to move block after other block 1`] = `\nArray [\n  Object {\n    \"key\": \"B\",\n  },\n  Object {\n    \"key\": \"C\",\n  },\n  Object {\n    \"key\": \"A\",\n  },\n]\n`;\n\nexports[`must be able to move block after other nested block 1`] = `\nArray [\n  Object {\n    \"children\": Array [\n      \"C\",\n      \"A\",\n    ],\n    \"key\": \"B\",\n    \"nextSibling\": \"D\",\n    \"parent\": null,\n    \"prevSibling\": null,\n  },\n  Object {\n    \"children\": Array [],\n    \"key\": \"C\",\n    \"nextSibling\": \"A\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n  },\n  Object {\n    \"children\": Array [],\n    \"key\": \"A\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n  },\n  Object {\n    \"children\": Array [\n      \"E\",\n    ],\n    \"key\": \"D\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n  },\n  Object {\n    \"children\": Array [],\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"D\",\n    \"prevSibling\": null,\n  },\n]\n`;\n\nexports[`must be able to move block and its children after other block 1`] = `\nArray [\n  Object {\n    \"children\": Array [],\n    \"key\": \"A\",\n    \"nextSibling\": \"D\",\n    \"parent\": null,\n    \"prevSibling\": null,\n  },\n  Object {\n    \"children\": Array [\n      \"E\",\n    ],\n    \"key\": \"D\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n  },\n  Object {\n    \"children\": Array [],\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"D\",\n    \"prevSibling\": null,\n  },\n  Object {\n    \"children\": Array [\n      \"C\",\n    ],\n    \"key\": \"B\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"D\",\n  },\n  Object {\n    \"children\": Array [],\n    \"key\": \"C\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n  },\n]\n`;\n\nexports[`must be able to move block and its children after other nested block 1`] = `\nArray [\n  Object {\n    \"children\": Array [],\n    \"key\": \"A\",\n    \"nextSibling\": \"D\",\n    \"parent\": null,\n    \"prevSibling\": null,\n  },\n  Object {\n    \"children\": Array [\n      \"E\",\n      \"B\",\n    ],\n    \"key\": \"D\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n  },\n  Object {\n    \"children\": Array [],\n    \"key\": \"E\",\n    \"nextSibling\": \"B\",\n    \"parent\": \"D\",\n    \"prevSibling\": null,\n  },\n  Object {\n    \"children\": Array [\n      \"C\",\n    ],\n    \"key\": \"B\",\n    \"nextSibling\": null,\n    \"parent\": \"D\",\n    \"prevSibling\": \"E\",\n  },\n  Object {\n    \"children\": Array [],\n    \"key\": \"C\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n  },\n]\n`;\n\nexports[`must be able to move block and its children before other block 1`] = `\nArray [\n  Object {\n    \"children\": Array [\n      \"C\",\n    ],\n    \"key\": \"B\",\n    \"nextSibling\": \"A\",\n    \"parent\": null,\n    \"prevSibling\": null,\n  },\n  Object {\n    \"children\": Array [],\n    \"key\": \"C\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n  },\n  Object {\n    \"children\": Array [],\n    \"key\": \"A\",\n    \"nextSibling\": \"D\",\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n  },\n  Object {\n    \"children\": Array [\n      \"E\",\n    ],\n    \"key\": \"D\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n  },\n  Object {\n    \"children\": Array [],\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"D\",\n    \"prevSibling\": null,\n  },\n]\n`;\n\nexports[`must be able to move block and its children before other nested block 1`] = `\nArray [\n  Object {\n    \"children\": Array [],\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n  },\n  Object {\n    \"children\": Array [\n      \"D\",\n      \"C\",\n    ],\n    \"key\": \"B\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n  },\n  Object {\n    \"children\": Array [\n      \"E\",\n    ],\n    \"key\": \"D\",\n    \"nextSibling\": \"C\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n  },\n  Object {\n    \"children\": Array [],\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"D\",\n    \"prevSibling\": null,\n  },\n  Object {\n    \"children\": Array [],\n    \"key\": \"C\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"D\",\n  },\n]\n`;\n\nexports[`must be able to move block before other block 1`] = `\nArray [\n  Object {\n    \"key\": \"C\",\n  },\n  Object {\n    \"key\": \"A\",\n  },\n  Object {\n    \"key\": \"B\",\n  },\n]\n`;\n\nexports[`must be able to move block before other nested block 1`] = `\nArray [\n  Object {\n    \"children\": Array [\n      \"A\",\n      \"C\",\n    ],\n    \"key\": \"B\",\n    \"nextSibling\": \"D\",\n    \"parent\": null,\n    \"prevSibling\": null,\n  },\n  Object {\n    \"children\": Array [],\n    \"key\": \"A\",\n    \"nextSibling\": \"C\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n  },\n  Object {\n    \"children\": Array [],\n    \"key\": \"C\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"A\",\n  },\n  Object {\n    \"children\": Array [\n      \"E\",\n    ],\n    \"key\": \"D\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n  },\n  Object {\n    \"children\": Array [],\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"D\",\n    \"prevSibling\": null,\n  },\n]\n`;\n\nexports[`must be able to move nested block after other block 1`] = `\nArray [\n  Object {\n    \"children\": Array [],\n    \"key\": \"A\",\n    \"nextSibling\": \"C\",\n    \"parent\": null,\n    \"prevSibling\": null,\n  },\n  Object {\n    \"children\": Array [],\n    \"key\": \"C\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n  },\n  Object {\n    \"children\": Array [],\n    \"key\": \"B\",\n    \"nextSibling\": \"D\",\n    \"parent\": null,\n    \"prevSibling\": \"C\",\n  },\n  Object {\n    \"children\": Array [\n      \"E\",\n    ],\n    \"key\": \"D\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n  },\n  Object {\n    \"children\": Array [],\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"D\",\n    \"prevSibling\": null,\n  },\n]\n`;\n\nexports[`must be able to move nested block before other block 1`] = `\nArray [\n  Object {\n    \"children\": Array [],\n    \"key\": \"C\",\n    \"nextSibling\": \"A\",\n    \"parent\": null,\n    \"prevSibling\": null,\n  },\n  Object {\n    \"children\": Array [],\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": \"C\",\n  },\n  Object {\n    \"children\": Array [],\n    \"key\": \"B\",\n    \"nextSibling\": \"D\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n  },\n  Object {\n    \"children\": Array [\n      \"E\",\n    ],\n    \"key\": \"D\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n  },\n  Object {\n    \"children\": Array [],\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"D\",\n    \"prevSibling\": null,\n  },\n]\n`;\n"
  },
  {
    "path": "src/model/transaction/__tests__/__snapshots__/randomizeBlockMapKeys-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must be able to randomize keys for ContentBlockNodes BlockMap and make orphan blocks become root blocks 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"nextSibling\": \"key1\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"key2\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key1\",\n    \"nextSibling\": \"key3\",\n    \"parent\": null,\n    \"prevSibling\": \"key0\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": null,\n    \"parent\": \"key1\",\n    \"prevSibling\": null,\n    \"text\": \"Fire\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"key1\",\n    \"text\": \"Gorilla\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must be able to randomize keys for ContentBlockNodes BlockMap and update reference links to the new keys 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"key1\",\n      \"key3\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"key2\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key1\",\n    \"nextSibling\": \"key3\",\n    \"parent\": \"key0\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"nextSibling\": null,\n    \"parent\": \"key1\",\n    \"prevSibling\": null,\n    \"text\": \"X\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"nextSibling\": null,\n    \"parent\": \"key0\",\n    \"prevSibling\": \"key1\",\n    \"text\": \"Y\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must be able to randomize keys for ContentBlocks BlockMap 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key0\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key1\",\n    \"text\": \"Beta\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"Charlie\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"Delta\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n"
  },
  {
    "path": "src/model/transaction/__tests__/__snapshots__/removeEntitiesAtEdges-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must ignore an entity that is entirely within the selection 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must not affect blockMap if there are no entities 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must not remove if cursor is at end of entity 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must not remove if cursor is at start of entity 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must not remove mutable entities 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove entities at both ends of selection 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove entity at end of selection 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove entity at start of selection 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove for non-collapsed cursor on multiple entities 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove for non-collapsed cursor within a single entity 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove if cursor is within entity 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove immutable entities 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove segmented entities 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n"
  },
  {
    "path": "src/model/transaction/__tests__/__snapshots__/removeRangeFromContentState-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must merge D and E when deleting range from end of D to start of E 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"DeltaElephant\",\n    \"type\": \"unstyled\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"unstyled\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`must preserve B and C since E has not been removed 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  \"E\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Elephant\",\n    \"type\": \"unstyled\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"unstyled\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`must remove B and all its children 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"Gorila\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`must remove E and F entirely when selection is from end of D to end of F on nested blocks 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  \"C\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  \"D\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"unstyled\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`must remove blocks entirely within the selection 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpt\",\n    \"type\": \"unstyled\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove from the beginning of the block 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"ha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove from the end of A to the end of B 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove from the end of A to the start of B 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"AlphaBravo\",\n    \"type\": \"unstyled\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove from the end of A to within B 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alphavo\",\n    \"type\": \"unstyled\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove from the start of A to the end of B 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove from the start of A to the start of B 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Bravo\",\n    \"type\": \"unstyled\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove from the start of A to within B 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"vo\",\n    \"type\": \"unstyled\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove from within A to the end of B 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alp\",\n    \"type\": \"unstyled\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove from within A to the start of B 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"AlpBravo\",\n    \"type\": \"unstyled\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove from within A to within B 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpvo\",\n    \"type\": \"unstyled\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove from within the block 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Ala\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must remove to the end of the block 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alp\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n\nexports[`must retain B since F has not been removed 1`] = `\nObject {\n  \"A\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"B\": Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  \"F\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"Fire\",\n    \"type\": \"unstyled\",\n  },\n  \"G\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"unstyled\",\n  },\n}\n`;\n\nexports[`must return the input ContentState if selection is collapsed 1`] = `\nObject {\n  \"a\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  \"b\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  \"c\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  \"d\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"e\": Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  \"f\": Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n}\n`;\n"
  },
  {
    "path": "src/model/transaction/__tests__/__snapshots__/splitBlockInContentState-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must convert empty list item ContentBlock to unstyled rather than split 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Elephant\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n]\n`;\n\nexports[`must split at the beginning of a block 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key1\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must split at the beginning of a nested ContentBlock 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"key7\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"key7\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key7\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Delta\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"key7\",\n    \"text\": \"Elephant\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \"\",\n    \"type\": \"unordered-list-item\",\n  },\n]\n`;\n\nexports[`must split at the beginning of a root ContentBlock 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"key6\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key6\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"key6\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Elephant\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \"\",\n    \"type\": \"unordered-list-item\",\n  },\n]\n`;\n\nexports[`must split at the end of a block 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key3\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must split at the end of a nested ContentBlock 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"key11\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"key11\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key11\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"key11\",\n    \"text\": \"Elephant\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \"\",\n    \"type\": \"unordered-list-item\",\n  },\n]\n`;\n\nexports[`must split at the end of a root ContentBlock 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"key10\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key10\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"key10\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Elephant\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \"\",\n    \"type\": \"unordered-list-item\",\n  },\n]\n`;\n\nexports[`must split within a block 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"a\",\n    \"text\": \"Alp\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key2\",\n    \"text\": \"ha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n      Object {\n        \"entity\": \"2\",\n        \"style\": Array [\n          \"BOLD\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"b\",\n    \"text\": \"Bravo\",\n    \"type\": \"unordered-list-item\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"c\",\n    \"text\": \"Test\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"d\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"e\",\n    \"text\": \"\",\n    \"type\": \"code-block\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [\n          \"ITALIC\",\n        ],\n      },\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"f\",\n    \"text\": \"Charlie\",\n    \"type\": \"blockquote\",\n  },\n]\n`;\n\nexports[`must split within a nested ContentBlock 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alpha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n      \"key9\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": \"key9\",\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Ele\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key9\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"E\",\n    \"text\": \"phant\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \"\",\n    \"type\": \"unordered-list-item\",\n  },\n]\n`;\n\nexports[`must split within a root ContentBlock 1`] = `\nArray [\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"A\",\n    \"nextSibling\": \"key8\",\n    \"parent\": null,\n    \"prevSibling\": null,\n    \"text\": \"Alp\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"key8\",\n    \"nextSibling\": \"B\",\n    \"parent\": null,\n    \"prevSibling\": \"A\",\n    \"text\": \"ha\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"C\",\n      \"F\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"B\",\n    \"nextSibling\": \"G\",\n    \"parent\": null,\n    \"prevSibling\": \"key8\",\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [\n      \"D\",\n      \"E\",\n    ],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"C\",\n    \"nextSibling\": \"F\",\n    \"parent\": \"B\",\n    \"prevSibling\": null,\n    \"text\": \"\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"D\",\n    \"nextSibling\": \"E\",\n    \"parent\": \"C\",\n    \"prevSibling\": null,\n    \"text\": \"Delta\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"E\",\n    \"nextSibling\": null,\n    \"parent\": \"C\",\n    \"prevSibling\": \"D\",\n    \"text\": \"Elephant\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"F\",\n    \"nextSibling\": null,\n    \"parent\": \"B\",\n    \"prevSibling\": \"C\",\n    \"text\": \"Fire\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n      Object {\n        \"entity\": null,\n        \"style\": Array [],\n      },\n    ],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"G\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"B\",\n    \"text\": \"Gorila\",\n    \"type\": \"unstyled\",\n  },\n  Object {\n    \"characterList\": Array [],\n    \"children\": Array [],\n    \"data\": Object {},\n    \"depth\": 0,\n    \"key\": \"H\",\n    \"nextSibling\": null,\n    \"parent\": null,\n    \"prevSibling\": \"G\",\n    \"text\": \"\",\n    \"type\": \"unordered-list-item\",\n  },\n]\n`;\n"
  },
  {
    "path": "src/model/transaction/__tests__/applyEntityToContentBlock-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst ContentBlock = require('ContentBlock');\n\nconst applyEntityToContentBlock = require('applyEntityToContentBlock');\n\nconst sampleBlock = new ContentBlock({\n  key: 'a',\n  text: 'Hello',\n});\n\nconst assertApplyEntityToContentBlock = (\n  start: number,\n  end: number,\n  entityKey: $TEMPORARY$string<'x'> = 'x',\n  contentBlock: ContentBlock = sampleBlock,\n) => {\n  expect(\n    applyEntityToContentBlock(contentBlock, start, end, entityKey).toJS(),\n  ).toMatchSnapshot();\n};\n\ntest('must apply from the start', () => {\n  assertApplyEntityToContentBlock(0, 2);\n});\n\ntest('must apply within', () => {\n  assertApplyEntityToContentBlock(1, 4);\n});\n\ntest('must apply at the end', () => {\n  assertApplyEntityToContentBlock(3, 5);\n});\n\ntest('must apply to the entire text', () => {\n  assertApplyEntityToContentBlock(0, 5);\n});\n"
  },
  {
    "path": "src/model/transaction/__tests__/applyEntityToContentState-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\nimport type ContentState from 'ContentState';\n\nconst SelectionState = require('SelectionState');\n\nconst applyEntityToContentState = require('applyEntityToContentState');\nconst getSampleStateForTesting = require('getSampleStateForTesting');\n\nconst {contentState, selectionState} = getSampleStateForTesting();\n\nconst initialBlock = contentState.getBlockMap().first();\nconst secondBlock = contentState.getBlockAfter(initialBlock.getKey());\n\nconst selectBlock = new SelectionState({\n  anchorKey: initialBlock.getKey(),\n  anchorOffset: 0,\n  focusKey: initialBlock.getKey(),\n  focusOffset: initialBlock.getLength(),\n});\n\nconst selectAdjacentBlocks = new SelectionState({\n  anchorKey: initialBlock.getKey(),\n  anchorOffset: 0,\n  focusKey: secondBlock?.getKey(),\n  focusOffset: secondBlock?.getLength(),\n});\n\nconst assertApplyEntityToContentState = (\n  entityKey: null | $TEMPORARY$string<'x'>,\n  selection: $FlowFixMe | SelectionState = selectionState,\n  content: ContentState = contentState,\n) => {\n  expect(\n    applyEntityToContentState(content, selection, entityKey)\n      .getBlockMap()\n      .toJS(),\n  ).toMatchSnapshot();\n};\n\ntest('must apply entity key', () => {\n  assertApplyEntityToContentState('x', selectBlock);\n});\n\ntest('must apply null entity', () => {\n  assertApplyEntityToContentState(null, selectBlock);\n});\n\ntest('must apply entity key accross multiple blocks', () => {\n  assertApplyEntityToContentState('x', selectAdjacentBlocks);\n});\n\ntest('must apply null entity key accross multiple blocks', () => {\n  assertApplyEntityToContentState(null, selectAdjacentBlocks);\n});\n"
  },
  {
    "path": "src/model/transaction/__tests__/getContentStateFragment-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\njest.mock('generateRandomKey');\n\nconst ContentBlock = require('ContentBlock');\nconst ContentBlockNode = require('ContentBlockNode');\nconst ContentState = require('ContentState');\nconst EditorState = require('EditorState');\nconst SelectionState = require('SelectionState');\n\nconst getContentStateFragment = require('getContentStateFragment');\nconst Immutable = require('immutable');\n\nconst {List} = Immutable;\n\nconst contentBlocks = [\n  new ContentBlock({\n    key: 'A',\n    text: 'Alpha',\n  }),\n  new ContentBlock({\n    key: 'B',\n    text: 'Beta',\n  }),\n  new ContentBlock({\n    key: 'C',\n    text: 'Charlie',\n  }),\n  new ContentBlock({\n    key: 'D',\n    text: 'Delta',\n  }),\n];\n\nconst contentBlockNodes = [\n  new ContentBlockNode({\n    key: 'A',\n    text: 'Alpha',\n    nextSibling: 'B',\n  }),\n  new ContentBlockNode({\n    key: 'B',\n    text: '',\n    children: List(['C']),\n    nextSibling: 'D',\n    prevSibling: 'A',\n  }),\n  new ContentBlockNode({\n    key: 'C',\n    parent: 'B',\n    text: 'Charlie',\n  }),\n  new ContentBlockNode({\n    key: 'D',\n    text: 'Delta',\n    prevSibling: 'B',\n  }),\n];\n\nconst DEFAULT_SELECTION = {\n  anchorKey: 'A',\n  anchorOffset: 0,\n  focusKey: 'D',\n  focusOffset: 0,\n  isBackward: false,\n};\n\nconst assertGetContentStateFragment = (\n  blocksArray: Array<ContentBlock | ContentBlockNode>,\n  selection: {\n    anchorKey?: string,\n    focusKey?: string,\n    focusOffset?: number,\n  } = {},\n) => {\n  const editor = EditorState.acceptSelection(\n    EditorState.createWithContent(\n      ContentState.createFromBlockArray([...blocksArray]),\n    ),\n    new SelectionState({\n      ...DEFAULT_SELECTION,\n      ...selection,\n    }),\n  );\n\n  expect(\n    getContentStateFragment(\n      editor.getCurrentContent(),\n      editor.getSelection(),\n    ).toJS(),\n  ).toMatchSnapshot();\n};\n\ntest('must be able to return all selected contentBlocks', () => {\n  assertGetContentStateFragment(contentBlocks, {\n    focusOffset: contentBlocks[3].getLength(),\n  });\n});\n\ntest('must be able to return all selected contentBlockNodes', () => {\n  assertGetContentStateFragment(contentBlockNodes, {\n    focusOffset: contentBlockNodes[3].getLength(),\n  });\n});\n\ntest('must be able to return contentBlocks selected within', () => {\n  assertGetContentStateFragment(contentBlocks, {\n    anchorKey: 'B',\n    focusKey: 'C',\n    focusOffset: contentBlockNodes[2].getLength(),\n  });\n});\n\ntest('must be able to return contentBlockNodes selected within', () => {\n  assertGetContentStateFragment(contentBlockNodes, {\n    anchorKey: 'B',\n    focusKey: 'C',\n    focusOffset: contentBlockNodes[2].getLength(),\n  });\n});\n\ntest('must be able to return first ContentBlock selected', () => {\n  assertGetContentStateFragment(contentBlocks, {\n    anchorKey: 'A',\n    focusKey: 'A',\n    focusOffset: contentBlocks[0].getLength(),\n  });\n});\n\ntest('must be able to return first ContentBlockNode selected', () => {\n  assertGetContentStateFragment(contentBlockNodes, {\n    anchorKey: 'A',\n    focusKey: 'A',\n    focusOffset: contentBlockNodes[0].getLength(),\n  });\n});\n\ntest('must be able to return last ContentBlock selected', () => {\n  assertGetContentStateFragment(contentBlocks, {\n    anchorKey: 'D',\n    focusKey: 'D',\n    focusOffset: contentBlocks[3].getLength(),\n  });\n});\n\ntest('must be able to return last ContentBlockNode selected', () => {\n  assertGetContentStateFragment(contentBlockNodes, {\n    anchorKey: 'D',\n    focusKey: 'D',\n    focusOffset: contentBlockNodes[3].getLength(),\n  });\n});\n"
  },
  {
    "path": "src/model/transaction/__tests__/insertFragmentIntoContentState-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\nimport type {BlockMap} from 'BlockMap';\nimport type ContentState from 'ContentState';\n\nconst BlockMapBuilder = require('BlockMapBuilder');\nconst ContentBlock = require('ContentBlock');\nconst ContentBlockNode = require('ContentBlockNode');\nconst SelectionState = require('SelectionState');\n\nconst getSampleStateForTesting = require('getSampleStateForTesting');\nconst Immutable = require('immutable');\nconst insertFragmentIntoContentState = require('insertFragmentIntoContentState');\nconst invariant = require('invariant');\n\njest.mock('generateRandomKey');\n\nconst {contentState, selectionState} = getSampleStateForTesting();\nconst {List, Map} = Immutable;\n\nconst DEFAULT_BLOCK_CONFIG = {\n  key: 'j',\n  type: 'unstyled',\n  text: 'xx',\n  data: Map({a: 1}),\n};\n\nconst initialBlock = contentState.getBlockMap().first();\n\nconst getInvariantViolation = (msg: string) => {\n  try {\n    /* eslint-disable-next-line */\n    invariant(false, msg);\n  } catch (e) {\n    return e;\n  }\n};\n\nconst createFragment = (\n  /* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's\n   * LTI update could not be added via codemod */\n  fragment = {},\n  experimentalTreeDataSupport: boolean = false,\n) => {\n  const ContentBlockNodeRecord = experimentalTreeDataSupport\n    ? ContentBlockNode\n    : ContentBlock;\n  const newFragment = Array.isArray(fragment) ? fragment : [fragment];\n\n  return BlockMapBuilder.createFromArray(\n    newFragment.map(\n      config =>\n        new ContentBlockNodeRecord({\n          ...DEFAULT_BLOCK_CONFIG,\n          ...config,\n        }),\n    ),\n  );\n};\n\n/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's\n * LTI update could not be added via codemod */\nconst createContentBlockNodeFragment = fragment => {\n  return createFragment(fragment, true);\n};\n\nconst assertInsertFragmentIntoContentState = (\n  fragment: BlockMap,\n  selection: $FlowFixMe | SelectionState = selectionState,\n  content: ContentState = contentState,\n) => {\n  expect(\n    insertFragmentIntoContentState(content, selection, fragment)\n      .getBlockMap()\n      .toIndexedSeq()\n      .toJS(),\n  ).toMatchSnapshot();\n};\n\ntest('must throw if no fragment is provided', () => {\n  const fragment = BlockMapBuilder.createFromArray([]);\n  expect(() => {\n    insertFragmentIntoContentState(contentState, selectionState, fragment);\n  }).toThrow();\n});\n\ntest('must apply fragment to the start', () => {\n  assertInsertFragmentIntoContentState(createFragment());\n});\n\ntest('must apply fragment to within block', () => {\n  assertInsertFragmentIntoContentState(\n    createFragment(),\n    selectionState.merge({\n      focusOffset: 2,\n      anchorOffset: 2,\n      isBackward: false,\n    }),\n  );\n});\n\ntest('must apply fragment at the end', () => {\n  assertInsertFragmentIntoContentState(\n    createFragment(),\n    selectionState.merge({\n      focusOffset: initialBlock.getLength(),\n      anchorOffset: initialBlock.getLength(),\n      isBackward: false,\n    }),\n  );\n});\n\ntest('must apply multiblock fragments', () => {\n  assertInsertFragmentIntoContentState(\n    createFragment([\n      DEFAULT_BLOCK_CONFIG,\n      {\n        key: 'k',\n        text: 'yy',\n        data: Map({b: 2}),\n      },\n    ]),\n  );\n});\n\ntest('must be able to insert a fragment with a single ContentBlockNode', () => {\n  const initialSelection = SelectionState.createEmpty('A');\n  const initialContent = contentState.setBlockMap(\n    createContentBlockNodeFragment([\n      {\n        key: 'A',\n        text: '',\n      },\n    ]),\n  );\n\n  assertInsertFragmentIntoContentState(\n    createContentBlockNodeFragment([\n      {\n        key: 'B',\n        text: 'some text',\n      },\n    ]),\n    initialSelection,\n    initialContent,\n  );\n});\n\ntest('must be able to insert fragment of ContentBlockNodes', () => {\n  const initialSelection = SelectionState.createEmpty('first');\n  const initialContent = contentState.setBlockMap(\n    createContentBlockNodeFragment([\n      {\n        key: 'first',\n        text: '',\n        nextSibling: 'second',\n      },\n      {\n        key: 'second',\n        text: '',\n        prevSibling: 'first',\n      },\n    ]),\n  );\n\n  assertInsertFragmentIntoContentState(\n    createContentBlockNodeFragment([\n      {\n        key: 'B',\n        text: '',\n        children: List(['C']),\n        nextSibling: 'E',\n      },\n      {\n        key: 'C',\n        parent: 'B',\n        text: '',\n        children: List(['D']),\n      },\n      {\n        key: 'D',\n        parent: 'C',\n        text: 'Delta',\n      },\n      {\n        key: 'E',\n        text: 'Elephant',\n        prevSibling: 'B',\n      },\n    ]),\n    initialSelection,\n    initialContent,\n  );\n});\n\ntest('must be able to insert fragment of ContentBlockNodes after nested block', () => {\n  const initialSelection = SelectionState.createEmpty('firstChild');\n  const initialContent = contentState.setBlockMap(\n    createContentBlockNodeFragment([\n      {\n        key: 'root',\n        text: '',\n        children: List(['firstChild', 'lastChild']),\n      },\n      {\n        key: 'firstChild',\n        parent: 'root',\n        text: '',\n        nextSibling: 'lastChild',\n      },\n      {\n        key: 'lastChild',\n        parent: 'root',\n        text: '',\n        prevSibling: 'firstChild',\n      },\n    ]),\n  );\n\n  assertInsertFragmentIntoContentState(\n    createContentBlockNodeFragment([\n      {\n        key: 'B',\n        text: '',\n        children: List(['C']),\n        nextSibling: 'E',\n      },\n      {\n        key: 'C',\n        parent: 'B',\n        text: '',\n        children: List(['D']),\n      },\n      {\n        key: 'D',\n        parent: 'C',\n        text: 'Delta',\n      },\n      {\n        key: 'E',\n        text: 'Elephant',\n        prevSibling: 'B',\n      },\n    ]),\n    initialSelection,\n    initialContent,\n  );\n});\n\ntest('must be able to insert a fragment of ContentBlockNodes while updating the target block with the first fragment block properties', () => {\n  const initialSelection = SelectionState.createEmpty('first');\n  const initialContent = contentState.setBlockMap(\n    createContentBlockNodeFragment([\n      {\n        key: 'first',\n        text: '',\n        nextSibling: 'second',\n      },\n      {\n        key: 'second',\n        text: '',\n        prevSibling: 'first',\n      },\n    ]),\n  );\n\n  assertInsertFragmentIntoContentState(\n    createContentBlockNodeFragment([\n      {\n        key: 'A',\n        text: 'Alpha',\n        nextSibling: 'B',\n      },\n      {\n        key: 'B',\n        text: '',\n        children: List(['C']),\n        prevSibling: 'A',\n      },\n      {\n        key: 'C',\n        parent: 'B',\n        text: '',\n        children: List(['D']),\n      },\n      {\n        key: 'D',\n        parent: 'C',\n        text: 'Delta',\n      },\n    ]),\n    initialSelection,\n    initialContent,\n  );\n});\n\ntest('must be able to insert a fragment of ContentBlockNodes while updating the target block with the first fragment block properties after nested block', () => {\n  const initialSelection = SelectionState.createEmpty('firstChild');\n  const initialContent = contentState.setBlockMap(\n    createContentBlockNodeFragment([\n      {\n        key: 'root',\n        text: '',\n        children: List(['firstChild', 'lastChild']),\n      },\n      {\n        key: 'firstChild',\n        parent: 'root',\n        text: '',\n        nextSibling: 'lastChild',\n      },\n      {\n        key: 'lastChild',\n        parent: 'root',\n        text: '',\n        prevSibling: 'firstChild',\n      },\n    ]),\n  );\n\n  assertInsertFragmentIntoContentState(\n    createContentBlockNodeFragment([\n      {\n        key: 'A',\n        text: 'Alpha',\n        nextSibling: 'B',\n      },\n      {\n        key: 'B',\n        text: '',\n        children: List(['C']),\n        prevSibling: 'A',\n        nextSibling: 'E',\n      },\n      {\n        key: 'C',\n        parent: 'B',\n        text: '',\n        children: List(['D']),\n      },\n      {\n        key: 'D',\n        parent: 'C',\n        text: 'Delta',\n      },\n      {\n        key: 'E',\n        text: 'Elephant',\n        prevSibling: 'B',\n      },\n    ]),\n    initialSelection,\n    initialContent,\n  );\n});\n\ntest('must throw an error when trying to apply ContentBlockNode fragments when selection is on a block that has children', () => {\n  const initialSelection = SelectionState.createEmpty('A');\n  const initialContent = contentState.setBlockMap(\n    createContentBlockNodeFragment([\n      {\n        key: 'A',\n        text: '',\n        children: List(['B']),\n      },\n      {\n        key: 'B',\n        text: 'child',\n        parent: 'A',\n      },\n    ]),\n  );\n\n  expect(() =>\n    insertFragmentIntoContentState(\n      initialContent,\n      initialSelection,\n      createContentBlockNodeFragment([\n        {\n          key: 'C',\n          text: 'some text',\n        },\n      ]),\n    ),\n  ).toThrow(\n    getInvariantViolation(\n      '`insertFragment` should not be called when a container node is selected.',\n    ),\n  );\n});\n"
  },
  {
    "path": "src/model/transaction/__tests__/insertIntoList-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\nimport type {List} from 'immutable';\n\nconst Immutable = require('immutable');\nconst insertIntoList = require('insertIntoList');\n\nconst SAMPLE_LIST = Immutable.List.of(0, 1, 2, 3, 4);\n\nconst assertAssertInsertIntoList = (\n  toInsert: List<number>,\n  offset: number = SAMPLE_LIST.size,\n  targetList: List<number> = SAMPLE_LIST,\n) => {\n  expect(insertIntoList(targetList, toInsert, offset)).toMatchSnapshot();\n};\n\ntest('must insert at end of list', () => {\n  assertAssertInsertIntoList(Immutable.List.of(100, 101, 102));\n});\n\ntest('must insert at beginning of list', () => {\n  assertAssertInsertIntoList(Immutable.List.of(100, 101, 102), 0);\n});\n\ntest('must insert within a list', () => {\n  assertAssertInsertIntoList(Immutable.List.of(100, 101, 102), 3);\n});\n"
  },
  {
    "path": "src/model/transaction/__tests__/insertTextIntoContentState-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\nimport type SelectionState from 'SelectionState';\n\nconst CharacterMetadata = require('CharacterMetadata');\nconst {BOLD} = require('SampleDraftInlineStyle');\n\nconst getSampleStateForTesting = require('getSampleStateForTesting');\nconst insertTextIntoContentState = require('insertTextIntoContentState');\n\nconst {contentState, selectionState} = getSampleStateForTesting();\n\nconst EMPTY = CharacterMetadata.EMPTY;\nconst initialBlock = contentState.getBlockMap().first();\n\nconst assertInsertTextIntoContentState = (\n  text: string | $TEMPORARY$string<'xx'>,\n  characterMetadata: $FlowFixMe | CharacterMetadata,\n  selection: $FlowFixMe | SelectionState = selectionState,\n) => {\n  expect(\n    insertTextIntoContentState(contentState, selection, text, characterMetadata)\n      .getBlockMap()\n      .toJS(),\n  ).toMatchSnapshot();\n};\n\ntest('must throw if selection is not collapsed', () => {\n  expect(() => {\n    insertTextIntoContentState(\n      contentState,\n      selectionState.set('focusOffset', 2),\n      'hey',\n      EMPTY,\n    );\n  }).toThrow();\n});\n\ntest('must return early if no text is provided', () => {\n  assertInsertTextIntoContentState('', EMPTY);\n});\n\ntest('must insert at the start', () => {\n  assertInsertTextIntoContentState(\n    'xx',\n    CharacterMetadata.create({style: BOLD}),\n  );\n});\n\ntest('must insert within block', () => {\n  assertInsertTextIntoContentState(\n    'xx',\n    CharacterMetadata.create({style: BOLD}),\n    selectionState.merge({\n      focusOffset: 2,\n      anchorOffset: 2,\n      isBackward: false,\n    }),\n  );\n});\n\ntest('must insert at the end', () => {\n  assertInsertTextIntoContentState(\n    'xx',\n    CharacterMetadata.create({style: BOLD}),\n    selectionState.merge({\n      focusOffset: initialBlock.getLength(),\n      anchorOffset: initialBlock.getLength(),\n      isBackward: false,\n    }),\n  );\n});\n"
  },
  {
    "path": "src/model/transaction/__tests__/moveBlockInContentState-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\njest.mock('generateRandomKey');\n\nconst ContentBlock = require('ContentBlock');\nconst ContentBlockNode = require('ContentBlockNode');\nconst ContentState = require('ContentState');\nconst EditorState = require('EditorState');\n\nconst Immutable = require('immutable');\nconst moveBlockInContentState = require('moveBlockInContentState');\n\nconst {List} = Immutable;\n\nconst contentBlocks = [\n  new ContentBlock({\n    key: 'A',\n    text: 'Alpha',\n  }),\n  new ContentBlock({\n    key: 'B',\n    text: 'Beta',\n  }),\n  new ContentBlock({\n    key: 'C',\n    text: 'Charlie',\n  }),\n];\n\nconst contentBlockNodes = [\n  new ContentBlockNode({\n    key: 'A',\n    text: 'Alpha',\n    nextSibling: 'B',\n  }),\n  new ContentBlockNode({\n    key: 'B',\n    text: '',\n    children: List(['C']),\n    nextSibling: 'D',\n    prevSibling: 'A',\n  }),\n  new ContentBlockNode({\n    key: 'C',\n    parent: 'B',\n    text: 'Charlie',\n  }),\n  new ContentBlockNode({\n    key: 'D',\n    text: '',\n    prevSibling: 'B',\n    children: List(['E']),\n  }),\n  new ContentBlockNode({\n    key: 'E',\n    parent: 'D',\n    text: 'Elephant',\n  }),\n];\n\n// doing this filtering to make the snapshot more precise/concise in what we test\nconst BLOCK_PROPS_BLACKLIST = [\n  'characterList',\n  'data',\n  'depth',\n  'text',\n  'type',\n];\n\nconst assertMoveBlockInContentState = (\n  blockToBeMovedKey: string,\n  targetBlockKey: string,\n  insertionMode: 'after' | 'before',\n  blocksArray: Array<ContentBlock | ContentBlockNode> = contentBlocks,\n) => {\n  const editor = EditorState.createWithContent(\n    ContentState.createFromBlockArray(blocksArray),\n  );\n  const contentState = editor.getCurrentContent();\n  const blockToBeMoved = contentState.getBlockForKey(blockToBeMovedKey);\n  const targetBlock = contentState.getBlockForKey(targetBlockKey);\n\n  expect(\n    moveBlockInContentState(\n      contentState,\n      blockToBeMoved,\n      targetBlock,\n      insertionMode,\n    )\n      .getBlockMap()\n      .toSetSeq()\n      .toArray()\n      .map(filter => filter.toJS())\n      .map(block =>\n        Object.keys(block)\n          .filter(prop => BLOCK_PROPS_BLACKLIST.indexOf(prop) === -1)\n          .reduce<{[string]: $FlowFixMe}>((acc, prop) => {\n            acc[prop] = block[prop];\n            return acc;\n          }, {}),\n      ),\n  ).toMatchSnapshot();\n};\n\ntest('must be able to move block before other block', () => {\n  assertMoveBlockInContentState('C', 'A', 'before');\n});\n\ntest('must be able to move block after other block', () => {\n  assertMoveBlockInContentState('A', 'C', 'after');\n});\n\ntest('must be able to move nested block before other block', () => {\n  assertMoveBlockInContentState('C', 'A', 'before', contentBlockNodes);\n});\n\ntest('must be able to move block before other nested block', () => {\n  assertMoveBlockInContentState('A', 'C', 'before', contentBlockNodes);\n});\n\ntest('must be able to move nested block after other block', () => {\n  assertMoveBlockInContentState('C', 'A', 'after', contentBlockNodes);\n});\n\ntest('must be able to move block after other nested block', () => {\n  assertMoveBlockInContentState('A', 'C', 'after', contentBlockNodes);\n});\n\ntest('must be able to move block and its children before other block', () => {\n  assertMoveBlockInContentState('B', 'A', 'before', contentBlockNodes);\n});\n\ntest('must be able to move block and its children after other block', () => {\n  assertMoveBlockInContentState('D', 'A', 'after', contentBlockNodes);\n});\n\ntest('must be able to move block and its children before other nested block', () => {\n  assertMoveBlockInContentState('D', 'C', 'before', contentBlockNodes);\n});\n\ntest('must be able to move block and its children after other nested block', () => {\n  assertMoveBlockInContentState('B', 'E', 'after', contentBlockNodes);\n});\n"
  },
  {
    "path": "src/model/transaction/__tests__/randomizeBlockMapKeys-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\njest.mock('generateRandomKey');\n\nconst BlockMapBuilder = require('BlockMapBuilder');\nconst ContentBlock = require('ContentBlock');\nconst ContentBlockNode = require('ContentBlockNode');\n\nconst Immutable = require('immutable');\nconst randomizeBlockMapKeys = require('randomizeBlockMapKeys');\n\nconst {List} = Immutable;\n\nconst assertRandomizeBlockMapKeys = (\n  blockMapArray: Array<ContentBlock | ContentBlockNode>,\n) => {\n  expect(\n    randomizeBlockMapKeys(BlockMapBuilder.createFromArray(blockMapArray))\n      .toIndexedSeq()\n      .toJS(),\n  ).toMatchSnapshot();\n};\n\nbeforeEach(() => {\n  jest.resetModules();\n});\n\ntest('must be able to randomize keys for ContentBlocks BlockMap', () => {\n  assertRandomizeBlockMapKeys([\n    new ContentBlock({\n      key: 'A',\n      text: 'Alpha',\n    }),\n    new ContentBlock({\n      key: 'B',\n      text: 'Beta',\n    }),\n    new ContentBlock({\n      key: 'C',\n      text: 'Charlie',\n    }),\n    new ContentBlock({\n      key: 'D',\n      text: 'Delta',\n    }),\n  ]);\n});\n\ntest('must be able to randomize keys for ContentBlockNodes BlockMap and update reference links to the new keys', () => {\n  assertRandomizeBlockMapKeys([\n    new ContentBlockNode({\n      key: 'A',\n      text: '',\n      children: List(['B', 'D']),\n    }),\n    new ContentBlockNode({\n      key: 'B',\n      parent: 'A',\n      children: List(['C']),\n      nextSibling: 'D',\n      text: '',\n    }),\n    new ContentBlockNode({\n      key: 'C',\n      parent: 'B',\n      text: 'X',\n    }),\n    new ContentBlockNode({\n      key: 'D',\n      parent: 'A',\n      prevSibling: 'B',\n      text: 'Y',\n    }),\n  ]);\n});\n\n/**\n * This could occur when extracting a fragment from a partial selection\n * the below case could happen when selecting blocks D to G from blockMap like:\n *\n *\n * A\n *   B\n *     C\n *       D - Delta\n *   E\n *     F - Fire\n *   g - gorilla\n *\n *\n * Selected (D to G) - Expected outcome:\n *\n * => We should remove all parent links from the orphan blocks then they should be treated as root nodes\n * making sure that next/pre links are amended accordingly\n */\ntest('must be able to randomize keys for ContentBlockNodes BlockMap and make orphan blocks become root blocks', () => {\n  assertRandomizeBlockMapKeys([\n    new ContentBlockNode({\n      key: 'D',\n      parent: 'C',\n      text: 'Delta',\n    }),\n    new ContentBlockNode({\n      key: 'E',\n      parent: 'A',\n      prevSibling: 'B',\n      nextSibling: 'G',\n      children: List(['F']),\n    }),\n    new ContentBlockNode({\n      key: 'F',\n      parent: 'E',\n      text: 'Fire',\n    }),\n    new ContentBlockNode({\n      key: 'G',\n      parent: 'A',\n      prevSibling: 'E',\n      text: 'Gorilla',\n    }),\n  ]);\n});\n"
  },
  {
    "path": "src/model/transaction/__tests__/removeEntitiesAtEdges-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\nimport type ContentState from 'ContentState';\nimport type SelectionState from 'SelectionState';\n\nconst DraftEntityInstance = require('DraftEntityInstance');\n\nconst applyEntityToContentBlock = require('applyEntityToContentBlock');\nconst getSampleStateForTesting = require('getSampleStateForTesting');\nconst removeEntitiesAtEdges = require('removeEntitiesAtEdges');\n\nconst {contentState: sampleContentState, selectionState} =\n  getSampleStateForTesting();\n\nconst selectionOnEntity = selectionState.merge({\n  anchorKey: 'b',\n  anchorOffset: 2,\n  focusKey: 'b',\n  focusOffset: 2,\n});\n\n// Creates an entity with the given key and mutability\nfunction ensureEntityWithMutability(\n  contentState: ContentState,\n  key: $TEMPORARY$string<'2'> | $TEMPORARY$string<'456'>,\n  mutability:\n    | $TEMPORARY$string<'IMMUTABLE'>\n    | $TEMPORARY$string<'MUTABLE'>\n    | $TEMPORARY$string<'SEGMENTED'>,\n) {\n  return contentState.setEntityMap(\n    contentState.getAllEntities().set(\n      key,\n      new DraftEntityInstance({\n        mutability,\n      }),\n    ),\n  );\n}\n\nconst assertRemoveEntitiesAtEdges = (\n  selection: $FlowFixMe | SelectionState,\n  mutability:\n    | $TEMPORARY$string<'IMMUTABLE'>\n    | $TEMPORARY$string<'MUTABLE'>\n    | $TEMPORARY$string<'SEGMENTED'> = 'IMMUTABLE',\n  content: ContentState = sampleContentState,\n) => {\n  const contentState = ensureEntityWithMutability(content, '2', mutability);\n  expect(\n    removeEntitiesAtEdges(contentState, selection).getBlockMap().toJS(),\n  ).toMatchSnapshot();\n};\n\ntest('must not affect blockMap if there are no entities', () => {\n  assertRemoveEntitiesAtEdges(selectionState);\n});\n\ntest('must not remove mutable entities', () => {\n  assertRemoveEntitiesAtEdges(selectionOnEntity, 'MUTABLE');\n});\n\ntest('must remove immutable entities', () => {\n  assertRemoveEntitiesAtEdges(selectionOnEntity, 'IMMUTABLE');\n});\n\ntest('must remove segmented entities', () => {\n  assertRemoveEntitiesAtEdges(selectionOnEntity, 'SEGMENTED');\n});\n\ntest('must not remove if cursor is at start of entity', () => {\n  assertRemoveEntitiesAtEdges(\n    selectionOnEntity.merge({\n      anchorOffset: 0,\n      focusOffset: 0,\n    }),\n  );\n});\n\ntest('must remove if cursor is within entity', () => {\n  assertRemoveEntitiesAtEdges(selectionOnEntity);\n});\n\ntest('must not remove if cursor is at end of entity', () => {\n  const length = sampleContentState.getBlockForKey('b').getLength();\n  assertRemoveEntitiesAtEdges(\n    selectionOnEntity.merge({\n      anchorOffset: length,\n      focusOffset: length,\n    }),\n  );\n});\n\ntest('must remove for non-collapsed cursor within a single entity', () => {\n  assertRemoveEntitiesAtEdges(selectionOnEntity.set('anchorOffset', 1));\n});\n\ntest('must remove for non-collapsed cursor on multiple entities', () => {\n  const block = sampleContentState.getBlockForKey('b');\n  const newBlock = applyEntityToContentBlock(block, 3, 5, '456');\n  const newBlockMap = sampleContentState.getBlockMap().set('b', newBlock);\n  let newContent = sampleContentState.setBlockMap(newBlockMap);\n  newContent = ensureEntityWithMutability(newContent, '456', 'IMMUTABLE');\n\n  assertRemoveEntitiesAtEdges(\n    selectionOnEntity.merge({\n      anchorOffset: 1,\n      focusOffset: 4,\n    }),\n    'IMMUTABLE',\n    newContent,\n  );\n});\n\ntest('must ignore an entity that is entirely within the selection', () => {\n  const block = sampleContentState.getBlockForKey('b');\n\n  // Remove entity from beginning and end of block.\n  let newBlock = applyEntityToContentBlock(block, 0, 1, null);\n  newBlock = applyEntityToContentBlock(newBlock, 4, 5, null);\n\n  const newBlockMap = sampleContentState.getBlockMap().set('b', newBlock);\n  const newContent = sampleContentState.setBlockMap(newBlockMap);\n\n  assertRemoveEntitiesAtEdges(\n    selectionOnEntity.merge({\n      anchorOffset: 0,\n      focusOffset: 5,\n    }),\n    'IMMUTABLE',\n    newContent,\n  );\n});\n\ntest('must remove entity at start of selection', () => {\n  assertRemoveEntitiesAtEdges(\n    selectionState.merge({\n      anchorKey: 'b',\n      anchorOffset: 3,\n      focusKey: 'c',\n      focusOffset: 3,\n    }),\n  );\n});\n\ntest('must remove entity at end of selection', () => {\n  assertRemoveEntitiesAtEdges(\n    selectionState.merge({\n      anchorKey: 'a',\n      anchorOffset: 3,\n      focusKey: 'b',\n      focusOffset: 3,\n    }),\n  );\n});\n\ntest('must remove entities at both ends of selection', () => {\n  const cBlock = sampleContentState.getBlockForKey('c');\n  const len = cBlock.getLength();\n  const modifiedC = applyEntityToContentBlock(cBlock, 0, len, '456');\n  const newBlockMap = sampleContentState.getBlockMap().set('c', modifiedC);\n  let newContent = sampleContentState.setBlockMap(newBlockMap);\n  newContent = ensureEntityWithMutability(newContent, '456', 'IMMUTABLE');\n\n  assertRemoveEntitiesAtEdges(\n    selectionState.merge({\n      anchorKey: 'b',\n      anchorOffset: 3,\n      focusKey: 'c',\n      focusOffset: 3,\n    }),\n    'IMMUTABLE',\n    newContent,\n  );\n});\n"
  },
  {
    "path": "src/model/transaction/__tests__/removeRangeFromContentState-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\nimport type ContentState from 'ContentState';\n\nconst BlockMapBuilder = require('BlockMapBuilder');\nconst ContentBlockNode = require('ContentBlockNode');\nconst SelectionState = require('SelectionState');\n\nconst getSampleStateForTesting = require('getSampleStateForTesting');\nconst Immutable = require('immutable');\nconst removeRangeFromContentState = require('removeRangeFromContentState');\n\nconst {List} = Immutable;\n\nconst {contentState, selectionState} = getSampleStateForTesting();\n\nconst contentBlockNodes = [\n  new ContentBlockNode({\n    key: 'A',\n    nextSibling: 'B',\n    text: 'Alpha',\n  }),\n  new ContentBlockNode({\n    key: 'B',\n    prevSibling: 'A',\n    nextSibling: 'G',\n    children: List(['C', 'F']),\n  }),\n  new ContentBlockNode({\n    parent: 'B',\n    key: 'C',\n    nextSibling: 'F',\n    children: List(['D', 'E']),\n  }),\n  new ContentBlockNode({\n    parent: 'C',\n    key: 'D',\n    nextSibling: 'E',\n    text: 'Delta',\n  }),\n  new ContentBlockNode({\n    parent: 'C',\n    key: 'E',\n    prevSibling: 'D',\n    text: 'Elephant',\n  }),\n  new ContentBlockNode({\n    parent: 'B',\n    key: 'F',\n    prevSibling: 'C',\n    text: 'Fire',\n  }),\n  new ContentBlockNode({\n    key: 'G',\n    prevSibling: 'B',\n    text: 'Gorila',\n  }),\n];\nconst treeSelectionState = SelectionState.createEmpty('A');\nconst treeContentState = contentState.setBlockMap(\n  BlockMapBuilder.createFromArray(contentBlockNodes),\n);\n\nconst assertRemoveRangeFromContentState = (\n  selection: $FlowFixMe | SelectionState,\n  content: ContentState = contentState,\n) => {\n  expect(\n    removeRangeFromContentState(content, selection).getBlockMap().toJS(),\n  ).toMatchSnapshot();\n};\n\nconst initialBlock = contentState.getBlockMap().first();\nconst secondBlock = contentState.getBlockMap().skip(1).first();\nconst selectionWithinA = selectionState.set('anchorOffset', 3);\nconst selectionFromEndOfA = selectionState.merge({\n  anchorOffset: initialBlock.getLength(),\n  focusOffset: initialBlock.getLength(),\n});\n\ntest('must return the input ContentState if selection is collapsed', () => {\n  assertRemoveRangeFromContentState(selectionState);\n});\n\ntest('must remove from the beginning of the block', () => {\n  // Remove from 0 to 3.\n  assertRemoveRangeFromContentState(selectionState.set('focusOffset', 3));\n});\n\ntest('must remove from within the block', () => {\n  // Remove from 2 to 4.\n  assertRemoveRangeFromContentState(\n    selectionState.merge({\n      anchorOffset: 2,\n      focusOffset: 4,\n    }),\n  );\n});\n\ntest('must remove to the end of the block', () => {\n  // Remove from 3 to end.\n  assertRemoveRangeFromContentState(\n    selectionState.merge({\n      anchorOffset: 3,\n      focusOffset: contentState.getBlockMap().first().getLength(),\n    }),\n  );\n});\n\ntest('must remove from the start of A to the start of B', () => {\n  // Block B is removed. Its contents replace the contents of block A,\n  // while the `type` of block A is preserved.\n  assertRemoveRangeFromContentState(selectionState.set('focusKey', 'b'));\n});\n\ntest('must remove from the start of A to within B', () => {\n  // A slice of block B contents replace the contents of block A,\n  // while the `type` of block A is preserved. Block B is removed.\n  assertRemoveRangeFromContentState(\n    selectionState.merge({\n      focusKey: 'b',\n      focusOffset: 3,\n    }),\n  );\n});\n\ntest('must remove from the start of A to the end of B', () => {\n  // Block A is effectively just emptied out, while block B is removed.\n  assertRemoveRangeFromContentState(\n    selectionState.merge({\n      focusKey: 'b',\n      focusOffset: secondBlock.getLength(),\n    }),\n  );\n});\n\ntest('must remove from within A to the start of B', () => {\n  assertRemoveRangeFromContentState(selectionWithinA.set('focusKey', 'b'));\n});\n\ntest('must remove from within A to within B', () => {\n  assertRemoveRangeFromContentState(\n    selectionWithinA.merge({\n      focusKey: 'b',\n      focusOffset: 3,\n    }),\n  );\n});\n\ntest('must remove from within A to the end of B', () => {\n  assertRemoveRangeFromContentState(\n    selectionWithinA.merge({\n      focusKey: 'b',\n      focusOffset: secondBlock.getLength(),\n    }),\n  );\n});\n\ntest('must remove from the end of A to the start of B', () => {\n  assertRemoveRangeFromContentState(\n    selectionFromEndOfA.merge({\n      focusKey: 'b',\n      focusOffset: 0,\n    }),\n  );\n});\n\ntest('must remove from the end of A to within B', () => {\n  assertRemoveRangeFromContentState(\n    selectionFromEndOfA.merge({\n      focusKey: 'b',\n      focusOffset: 3,\n    }),\n  );\n});\n\ntest('must remove from the end of A to the end of B', () => {\n  assertRemoveRangeFromContentState(\n    selectionFromEndOfA.merge({\n      focusKey: 'b',\n      focusOffset: secondBlock.getLength(),\n    }),\n  );\n});\n\ntest('must remove blocks entirely within the selection', () => {\n  assertRemoveRangeFromContentState(\n    selectionState.merge({\n      anchorOffset: 3,\n      focusKey: 'c',\n      focusOffset: 3,\n    }),\n  );\n});\n\ntest('must remove E and F entirely when selection is from end of D to end of F on nested blocks', () => {\n  assertRemoveRangeFromContentState(\n    treeSelectionState.merge({\n      anchorKey: 'D',\n      focusKey: 'F',\n      anchorOffset: contentBlockNodes[3].getLength(),\n      focusOffset: contentBlockNodes[5].getLength(),\n    }),\n    treeContentState,\n  );\n});\n\ntest('must preserve B and C since E has not been removed', () => {\n  assertRemoveRangeFromContentState(\n    treeSelectionState.merge({\n      anchorKey: 'A',\n      focusKey: 'D',\n      anchorOffset: contentBlockNodes[0].getLength(),\n      focusOffset: contentBlockNodes[3].getLength(),\n    }),\n    treeContentState,\n  );\n});\n\ntest('must remove B and all its children', () => {\n  assertRemoveRangeFromContentState(\n    treeSelectionState.merge({\n      anchorKey: 'A',\n      focusKey: 'F',\n      anchorOffset: contentBlockNodes[0].getLength(),\n      focusOffset: contentBlockNodes[5].getLength(),\n    }),\n    treeContentState,\n  );\n});\n\ntest('must retain B since F has not been removed', () => {\n  assertRemoveRangeFromContentState(\n    treeSelectionState.merge({\n      anchorKey: 'A',\n      focusKey: 'E',\n      anchorOffset: contentBlockNodes[0].getLength(),\n      focusOffset: contentBlockNodes[4].getLength(),\n    }),\n    treeContentState,\n  );\n});\n\n// Simulates having collapsed selection at start of Elephant and hitting backspace\n// We expect Elephant will be merged with previous block, Delta\ntest('must merge D and E when deleting range from end of D to start of E', () => {\n  assertRemoveRangeFromContentState(\n    treeSelectionState.merge({\n      anchorKey: 'D',\n      focusKey: 'E',\n      anchorOffset: contentBlockNodes[3].getLength(), // end of D\n      focusOffset: 0, // start of E\n    }),\n    treeContentState,\n  );\n});\n"
  },
  {
    "path": "src/model/transaction/__tests__/splitBlockInContentState-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\nimport type ContentState from 'ContentState';\n\nconst BlockMapBuilder = require('BlockMapBuilder');\nconst ContentBlockNode = require('ContentBlockNode');\nconst SelectionState = require('SelectionState');\n\nconst getSampleStateForTesting = require('getSampleStateForTesting');\nconst Immutable = require('immutable');\nconst splitBlockInContentState = require('splitBlockInContentState');\n\njest.mock('generateRandomKey');\n\nconst {List} = Immutable;\n\nconst {contentState, selectionState} = getSampleStateForTesting();\n\nconst contentBlockNodes = [\n  new ContentBlockNode({\n    key: 'A',\n    nextSibling: 'B',\n    text: 'Alpha',\n  }),\n  new ContentBlockNode({\n    key: 'B',\n    prevSibling: 'A',\n    nextSibling: 'G',\n    children: List(['C', 'F']),\n  }),\n  new ContentBlockNode({\n    parent: 'B',\n    key: 'C',\n    nextSibling: 'F',\n    children: List(['D', 'E']),\n  }),\n  new ContentBlockNode({\n    parent: 'C',\n    key: 'D',\n    nextSibling: 'E',\n    text: 'Delta',\n  }),\n  new ContentBlockNode({\n    parent: 'C',\n    key: 'E',\n    prevSibling: 'D',\n    text: 'Elephant',\n  }),\n  new ContentBlockNode({\n    parent: 'B',\n    key: 'F',\n    prevSibling: 'C',\n    text: 'Fire',\n  }),\n  new ContentBlockNode({\n    key: 'G',\n    prevSibling: 'B',\n    text: 'Gorila',\n  }),\n  new ContentBlockNode({\n    key: 'H',\n    prevSibling: 'G',\n    text: '',\n    type: 'unordered-list-item',\n  }),\n];\nconst treeSelectionState = SelectionState.createEmpty('A');\nconst treeContentState = contentState.setBlockMap(\n  BlockMapBuilder.createFromArray(contentBlockNodes),\n);\n\nconst assertSplitBlockInContentState = (\n  selection: $FlowFixMe | SelectionState,\n  content: ContentState = contentState,\n) => {\n  expect(\n    splitBlockInContentState(content, selection)\n      .getBlockMap()\n      .toIndexedSeq()\n      .toJS(),\n  ).toMatchSnapshot();\n};\n\ntest('must be restricted to collapsed selections', () => {\n  expect(() => {\n    const nonCollapsed = selectionState.set('focusOffset', 1);\n    return splitBlockInContentState(contentState, nonCollapsed);\n  }).toThrow();\n\n  expect(() => {\n    return splitBlockInContentState(contentState, selectionState);\n  }).not.toThrow();\n});\n\ntest('must split at the beginning of a block', () => {\n  assertSplitBlockInContentState(selectionState);\n});\n\ntest('must split within a block', () => {\n  const SPLIT_OFFSET = 3;\n\n  assertSplitBlockInContentState(\n    selectionState.merge({\n      anchorOffset: SPLIT_OFFSET,\n      focusOffset: SPLIT_OFFSET,\n    }),\n  );\n});\n\ntest('must split at the end of a block', () => {\n  const SPLIT_OFFSET = contentState.getBlockMap().first().getLength();\n\n  assertSplitBlockInContentState(\n    selectionState.merge({\n      anchorOffset: SPLIT_OFFSET,\n      focusOffset: SPLIT_OFFSET,\n    }),\n  );\n});\n\ntest('must be restricted to collapsed selections for ContentBlocks', () => {\n  expect(() => {\n    const nonCollapsed = treeSelectionState.set('focusOffset', 1);\n    return splitBlockInContentState(treeContentState, nonCollapsed);\n  }).toThrow();\n\n  expect(() => {\n    return splitBlockInContentState(treeContentState, treeSelectionState);\n  }).not.toThrow();\n});\n\ntest('must be restricted to ContentBlocks that do not have children', () => {\n  expect(() => {\n    const invalidSelection = treeSelectionState.merge({\n      anchorKey: 'B',\n      focusKey: 'B',\n    });\n    return splitBlockInContentState(treeContentState, invalidSelection);\n  }).toThrow();\n});\n\ntest('must split at the beginning of a root ContentBlock', () => {\n  assertSplitBlockInContentState(treeSelectionState, treeContentState);\n});\n\ntest('must split at the beginning of a nested ContentBlock', () => {\n  assertSplitBlockInContentState(\n    treeSelectionState.merge({\n      anchorKey: 'D',\n      focusKey: 'D',\n    }),\n    treeContentState,\n  );\n});\n\ntest('must split within a root ContentBlock', () => {\n  const SPLIT_OFFSET = 3;\n  assertSplitBlockInContentState(\n    treeSelectionState.merge({\n      anchorOffset: SPLIT_OFFSET,\n      focusOffset: SPLIT_OFFSET,\n    }),\n    treeContentState,\n  );\n});\n\ntest('must split within a nested ContentBlock', () => {\n  const SPLIT_OFFSET = 3;\n  assertSplitBlockInContentState(\n    treeSelectionState.merge({\n      anchorOffset: SPLIT_OFFSET,\n      focusOffset: SPLIT_OFFSET,\n      anchorKey: 'E',\n      focusKey: 'E',\n    }),\n    treeContentState,\n  );\n});\n\ntest('must split at the end of a root ContentBlock', () => {\n  const SPLIT_OFFSET = contentBlockNodes[0].getLength();\n  assertSplitBlockInContentState(\n    treeSelectionState.merge({\n      anchorOffset: SPLIT_OFFSET,\n      focusOffset: SPLIT_OFFSET,\n    }),\n    treeContentState,\n  );\n});\n\ntest('must split at the end of a nested ContentBlock', () => {\n  const SPLIT_OFFSET = contentBlockNodes[3].getLength();\n  assertSplitBlockInContentState(\n    treeSelectionState.merge({\n      anchorOffset: SPLIT_OFFSET,\n      focusOffset: SPLIT_OFFSET,\n      anchorKey: 'D',\n      focusKey: 'D',\n    }),\n    treeContentState,\n  );\n});\n\ntest('must convert empty list item ContentBlock to unstyled rather than split', () => {\n  assertSplitBlockInContentState(\n    treeSelectionState.merge({\n      anchorOffset: 0,\n      focusOffset: 0,\n      anchorKey: 'H',\n      focusKey: 'H',\n    }),\n    treeContentState,\n  );\n});\n"
  },
  {
    "path": "src/model/transaction/adjustBlockDepthForContentState.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type ContentState from 'ContentState';\nimport type SelectionState from 'SelectionState';\n\nfunction adjustBlockDepthForContentState(\n  contentState: ContentState,\n  selectionState: SelectionState,\n  adjustment: number,\n  maxDepth?: number,\n): ContentState {\n  const startKey = selectionState.getStartKey();\n  const endKey = selectionState.getEndKey();\n  let blockMap = contentState.getBlockMap();\n  const blocks = blockMap\n    .toSeq()\n    .skipUntil((_, k) => k === startKey)\n    .takeUntil((_, k) => k === endKey)\n    .concat([[endKey, blockMap.get(endKey)]])\n    .map(block => {\n      let depth = block.getDepth() + adjustment;\n      depth = Math.max(0, depth);\n      if (maxDepth != null) {\n        depth = Math.min(depth, maxDepth);\n      }\n      return block.set('depth', depth);\n    });\n\n  blockMap = blockMap.merge(blocks);\n\n  return contentState.merge({\n    blockMap,\n    selectionBefore: selectionState,\n    selectionAfter: selectionState,\n  });\n}\n\nmodule.exports = adjustBlockDepthForContentState;\n"
  },
  {
    "path": "src/model/transaction/applyEntityToContentBlock.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\n\nconst CharacterMetadata = require('CharacterMetadata');\n\nfunction applyEntityToContentBlock(\n  contentBlock: BlockNodeRecord,\n  startArg: number,\n  end: number,\n  entityKey: ?string,\n): BlockNodeRecord {\n  let start = startArg;\n  let characterList = contentBlock.getCharacterList();\n  while (start < end) {\n    characterList = characterList.set(\n      start,\n      CharacterMetadata.applyEntity(characterList.get(start), entityKey),\n    );\n    start++;\n  }\n  return contentBlock.set('characterList', characterList);\n}\n\nmodule.exports = applyEntityToContentBlock;\n"
  },
  {
    "path": "src/model/transaction/applyEntityToContentState.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type ContentState from 'ContentState';\nimport type SelectionState from 'SelectionState';\n\nconst applyEntityToContentBlock = require('applyEntityToContentBlock');\nconst Immutable = require('immutable');\n\nfunction applyEntityToContentState(\n  contentState: ContentState,\n  selectionState: SelectionState,\n  entityKey: ?string,\n): ContentState {\n  const blockMap = contentState.getBlockMap();\n  const startKey = selectionState.getStartKey();\n  const startOffset = selectionState.getStartOffset();\n  const endKey = selectionState.getEndKey();\n  const endOffset = selectionState.getEndOffset();\n\n  const newBlocks = blockMap\n    .skipUntil((_, k) => k === startKey)\n    .takeUntil((_, k) => k === endKey)\n    .toOrderedMap()\n    .merge(Immutable.OrderedMap([[endKey, blockMap.get(endKey)]]))\n    .map((block, blockKey) => {\n      const sliceStart = blockKey === startKey ? startOffset : 0;\n      const sliceEnd = blockKey === endKey ? endOffset : block.getLength();\n      return applyEntityToContentBlock(block, sliceStart, sliceEnd, entityKey);\n    });\n\n  return contentState.merge({\n    blockMap: blockMap.merge(newBlocks),\n    selectionBefore: selectionState,\n    selectionAfter: selectionState,\n  });\n}\n\nmodule.exports = applyEntityToContentState;\n"
  },
  {
    "path": "src/model/transaction/exploration/__tests__/__snapshots__/getNextDelimiterBlockKey-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`must find its next delimiter when block does not have siblings 1`] = `\"D\"`;\n\nexports[`must find its next sibling when has siblings 1`] = `\"F\"`;\n\nexports[`must return null when block is ContentBlock 1`] = `null`;\n\nexports[`must return null when block is the last block 1`] = `null`;\n\nexports[`must return null when only blocks after it are its own descendants 1`] = `null`;\n"
  },
  {
    "path": "src/model/transaction/exploration/__tests__/getNextDelimiterBlockKey-test.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\njest.mock('generateRandomKey');\n\nconst ContentBlock = require('ContentBlock');\nconst ContentBlockNode = require('ContentBlockNode');\nconst ContentState = require('ContentState');\nconst EditorState = require('EditorState');\n\nconst getNextDelimiterBlockKey = require('getNextDelimiterBlockKey');\nconst Immutable = require('immutable');\n\nconst {List} = Immutable;\n\nconst contentBlocks = [\n  new ContentBlock({\n    key: 'A',\n    text: 'Alpha',\n  }),\n  new ContentBlock({\n    key: 'B',\n    text: 'Beta',\n  }),\n  new ContentBlock({\n    key: 'C',\n    text: 'Charlie',\n  }),\n];\n\nconst contentBlockNodes = [\n  new ContentBlockNode({\n    key: 'A',\n    text: 'Alpha',\n    nextSibling: 'B',\n  }),\n  new ContentBlockNode({\n    key: 'B',\n    text: '',\n    children: List(['C']),\n    nextSibling: 'D',\n    prevSibling: 'A',\n  }),\n  new ContentBlockNode({\n    key: 'C',\n    parent: 'B',\n    text: 'Charlie',\n  }),\n  new ContentBlockNode({\n    key: 'D',\n    text: '',\n    prevSibling: 'B',\n    children: List(['E', 'F']),\n  }),\n  new ContentBlockNode({\n    key: 'E',\n    parent: 'D',\n    nextSibling: 'F',\n    text: 'Elephant',\n  }),\n  new ContentBlockNode({\n    key: 'F',\n    parent: 'D',\n    prevSibling: 'E',\n    text: 'Fire',\n  }),\n];\n\nconst assertGetNextDelimiterBlockKey = (\n  targetBlockKey: string,\n  blocksArray: Array<ContentBlock | ContentBlockNode> = contentBlockNodes,\n) => {\n  const editor = EditorState.createWithContent(\n    ContentState.createFromBlockArray(blocksArray),\n  );\n  const contentState = editor.getCurrentContent();\n  const targetBlock = contentState.getBlockForKey(targetBlockKey);\n\n  expect(\n    getNextDelimiterBlockKey(targetBlock, contentState.getBlockMap()),\n  ).toMatchSnapshot();\n};\n\ntest('must return null when block is ContentBlock', () => {\n  assertGetNextDelimiterBlockKey('A', contentBlocks);\n});\n\ntest('must return null when only blocks after it are its own descendants', () => {\n  assertGetNextDelimiterBlockKey('D');\n});\n\ntest('must return null when block is the last block', () => {\n  assertGetNextDelimiterBlockKey('F');\n});\n\ntest('must find its next sibling when has siblings', () => {\n  assertGetNextDelimiterBlockKey('E');\n});\n\ntest('must find its next delimiter when block does not have siblings', () => {\n  assertGetNextDelimiterBlockKey('C');\n});\n"
  },
  {
    "path": "src/model/transaction/exploration/getNextDelimiterBlockKey.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * This is unstable and not part of the public API and should not be used by\n * production systems. This file may be update/removed without notice.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\nimport type {BlockMap} from 'BlockMap';\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type ContentBlock from 'ContentBlock';\n\nconst ContentBlockNode = require('ContentBlockNode');\n\nconst getNextDelimiterBlockKey = (\n  block: BlockNodeRecord,\n  blockMap: BlockMap,\n): ?string => {\n  const isExperimentalTreeBlock = block instanceof ContentBlockNode;\n\n  if (!isExperimentalTreeBlock) {\n    return null;\n  }\n\n  const nextSiblingKey = block.getNextSiblingKey();\n\n  if (nextSiblingKey) {\n    return nextSiblingKey;\n  }\n\n  const parent = block.getParentKey();\n\n  if (!parent) {\n    return null;\n  }\n\n  let nextNonDescendantBlock: ?(\n    | ContentBlock\n    | BlockNodeRecord\n    | ContentBlockNode\n  ) = blockMap.get(parent);\n  while (\n    nextNonDescendantBlock &&\n    !nextNonDescendantBlock.getNextSiblingKey()\n  ) {\n    const parentKey = nextNonDescendantBlock.getParentKey();\n    nextNonDescendantBlock = parentKey ? blockMap.get(parentKey) : null;\n  }\n\n  if (!nextNonDescendantBlock) {\n    return null;\n  }\n\n  return nextNonDescendantBlock.getNextSiblingKey();\n};\n\nmodule.exports = getNextDelimiterBlockKey;\n"
  },
  {
    "path": "src/model/transaction/getContentStateFragment.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockMap} from 'BlockMap';\nimport type ContentState from 'ContentState';\nimport type SelectionState from 'SelectionState';\n\nconst randomizeBlockMapKeys = require('randomizeBlockMapKeys');\nconst removeEntitiesAtEdges = require('removeEntitiesAtEdges');\n\nconst getContentStateFragment = (\n  contentState: ContentState,\n  selectionState: SelectionState,\n): BlockMap => {\n  const startKey = selectionState.getStartKey();\n  const startOffset = selectionState.getStartOffset();\n  const endKey = selectionState.getEndKey();\n  const endOffset = selectionState.getEndOffset();\n\n  // Edge entities should be stripped to ensure that we don't preserve\n  // invalid partial entities when the fragment is reused. We do, however,\n  // preserve entities that are entirely within the selection range.\n  const contentWithoutEdgeEntities = removeEntitiesAtEdges(\n    contentState,\n    selectionState,\n  );\n\n  const blockMap = contentWithoutEdgeEntities.getBlockMap();\n  const blockKeys = blockMap.keySeq();\n  const startIndex = blockKeys.indexOf(startKey);\n  const endIndex = blockKeys.indexOf(endKey) + 1;\n\n  return randomizeBlockMapKeys(\n    blockMap.slice(startIndex, endIndex).map((block, blockKey) => {\n      const text = block.getText();\n      const chars = block.getCharacterList();\n\n      if (startKey === endKey) {\n        return block.merge({\n          text: text.slice(startOffset, endOffset),\n          characterList: chars.slice(startOffset, endOffset),\n        });\n      }\n\n      if (blockKey === startKey) {\n        return block.merge({\n          text: text.slice(startOffset),\n          characterList: chars.slice(startOffset),\n        });\n      }\n\n      if (blockKey === endKey) {\n        return block.merge({\n          text: text.slice(0, endOffset),\n          characterList: chars.slice(0, endOffset),\n        });\n      }\n\n      return block;\n    }),\n  );\n};\n\nmodule.exports = getContentStateFragment;\n"
  },
  {
    "path": "src/model/transaction/getSampleStateForTesting.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nconst BlockMapBuilder = require('BlockMapBuilder');\nconst CharacterMetadata = require('CharacterMetadata');\nconst ContentBlock = require('ContentBlock');\nconst ContentState = require('ContentState');\nconst EditorState = require('EditorState');\nconst SampleDraftInlineStyle = require('SampleDraftInlineStyle');\nconst SelectionState = require('SelectionState');\n\nconst Immutable = require('immutable');\n\nconst {BOLD, ITALIC} = SampleDraftInlineStyle;\nconst ENTITY_KEY = '2';\n\nconst BLOCKS = [\n  new ContentBlock({\n    key: 'a',\n    type: 'unstyled',\n    text: 'Alpha',\n    characterList: Immutable.List(Immutable.Repeat(CharacterMetadata.EMPTY, 5)),\n  }),\n  new ContentBlock({\n    key: 'b',\n    type: 'unordered-list-item',\n    text: 'Bravo',\n    characterList: Immutable.List(\n      Immutable.Repeat(\n        CharacterMetadata.create({style: BOLD, entity: ENTITY_KEY}),\n        5,\n      ),\n    ),\n  }),\n  new ContentBlock({\n    key: 'c',\n    type: 'code-block',\n    text: 'Test',\n    characterList: Immutable.List(Immutable.Repeat(CharacterMetadata.EMPTY, 4)),\n  }),\n  new ContentBlock({\n    key: 'd',\n    type: 'code-block',\n    text: '',\n    characterList: Immutable.List(),\n  }),\n  new ContentBlock({\n    key: 'e',\n    type: 'code-block',\n    text: '',\n    characterList: Immutable.List(),\n  }),\n  new ContentBlock({\n    key: 'f',\n    type: 'blockquote',\n    text: 'Charlie',\n    characterList: Immutable.List(\n      Immutable.Repeat(\n        CharacterMetadata.create({style: ITALIC, entity: null}),\n        7,\n      ),\n    ),\n  }),\n];\n\nconst selectionState = new SelectionState({\n  anchorKey: 'a',\n  anchorOffset: 0,\n  focusKey: 'a',\n  focusOffset: 0,\n  isBackward: false,\n  hasFocus: true,\n});\n\nconst blockMap = BlockMapBuilder.createFromArray(BLOCKS);\nconst contentState = new ContentState({\n  blockMap,\n  entityMap: Immutable.OrderedMap(),\n  selectionBefore: selectionState,\n  selectionAfter: selectionState,\n}).createEntity('IMAGE', 'IMMUTABLE', null);\n\nlet editorState = EditorState.createWithContent(contentState);\neditorState = EditorState.forceSelection(editorState, selectionState);\n\nconst getSampleStateForTesting = (): {\n  editorState: EditorState,\n  contentState: ContentState,\n  selectionState: SelectionState,\n} => {\n  return {editorState, contentState, selectionState};\n};\n\nmodule.exports = getSampleStateForTesting;\n"
  },
  {
    "path": "src/model/transaction/insertFragmentIntoContentState.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockMap} from 'BlockMap';\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type ContentState from 'ContentState';\nimport type SelectionState from 'SelectionState';\n\nconst BlockMapBuilder = require('BlockMapBuilder');\nconst ContentBlockNode = require('ContentBlockNode');\n\nconst Immutable = require('immutable');\nconst insertIntoList = require('insertIntoList');\nconst invariant = require('invariant');\nconst randomizeBlockMapKeys = require('randomizeBlockMapKeys');\n\nconst {List} = Immutable;\n\nexport type BlockDataMergeBehavior =\n  | 'REPLACE_WITH_NEW_DATA'\n  | 'MERGE_OLD_DATA_TO_NEW_DATA';\n\nconst updateExistingBlock = (\n  contentState: ContentState,\n  selectionState: SelectionState,\n  blockMap: BlockMap,\n  fragmentBlock: BlockNodeRecord,\n  targetKey: string,\n  targetOffset: number,\n  mergeBlockData?: BlockDataMergeBehavior = 'REPLACE_WITH_NEW_DATA',\n): ContentState => {\n  const targetBlock = blockMap.get(targetKey);\n  const text = targetBlock.getText();\n  const chars = targetBlock.getCharacterList();\n  const finalKey = targetKey;\n  const finalOffset = targetOffset + fragmentBlock.getText().length;\n\n  let data = null;\n\n  switch (mergeBlockData) {\n    case 'MERGE_OLD_DATA_TO_NEW_DATA':\n      data = fragmentBlock.getData().merge(targetBlock.getData());\n      break;\n    case 'REPLACE_WITH_NEW_DATA':\n      data = fragmentBlock.getData();\n      break;\n  }\n\n  let type = targetBlock.getType();\n  if (text && type === 'unstyled') {\n    type = fragmentBlock.getType();\n  }\n\n  const newBlock = targetBlock.merge({\n    text:\n      text.slice(0, targetOffset) +\n      fragmentBlock.getText() +\n      text.slice(targetOffset),\n    characterList: insertIntoList(\n      chars,\n      fragmentBlock.getCharacterList(),\n      targetOffset,\n    ),\n    type,\n    data,\n  });\n\n  return contentState.merge({\n    blockMap: blockMap.set(targetKey, newBlock),\n    selectionBefore: selectionState,\n    selectionAfter: selectionState.merge({\n      anchorKey: finalKey,\n      anchorOffset: finalOffset,\n      focusKey: finalKey,\n      focusOffset: finalOffset,\n      isBackward: false,\n    }),\n  });\n};\n\n/**\n * Appends text/characterList from the fragment first block to\n * target block.\n */\nconst updateHead = (\n  block: BlockNodeRecord,\n  targetOffset: number,\n  fragment: BlockMap,\n): BlockNodeRecord => {\n  const text = block.getText();\n  const chars = block.getCharacterList();\n\n  // Modify head portion of block.\n  const headText = text.slice(0, targetOffset);\n  const headCharacters = chars.slice(0, targetOffset);\n  const appendToHead = fragment.first();\n\n  return block.merge({\n    text: headText + appendToHead.getText(),\n    characterList: headCharacters.concat(appendToHead.getCharacterList()),\n    type: headText ? block.getType() : appendToHead.getType(),\n    data: appendToHead.getData(),\n  });\n};\n\n/**\n * Appends offset text/characterList from the target block to the last\n * fragment block.\n */\nconst updateTail = (\n  block: BlockNodeRecord,\n  targetOffset: number,\n  fragment: BlockMap,\n): BlockNodeRecord => {\n  // Modify tail portion of block.\n  const text = block.getText();\n  const chars = block.getCharacterList();\n\n  // Modify head portion of block.\n  const blockSize = text.length;\n  const tailText = text.slice(targetOffset, blockSize);\n  const tailCharacters = chars.slice(targetOffset, blockSize);\n  const prependToTail = fragment.last();\n\n  return prependToTail.merge({\n    text: prependToTail.getText() + tailText,\n    characterList: prependToTail.getCharacterList().concat(tailCharacters),\n    data: prependToTail.getData(),\n  });\n};\n\nconst getRootBlocks = (\n  block: ContentBlockNode,\n  blockMap: BlockMap,\n): Array<string> => {\n  const headKey = block.getKey();\n  let rootBlock = block;\n  const rootBlocks = [];\n\n  // sometimes the fragment head block will not be part of the blockMap itself this can happen when\n  // the fragment head is used to update the target block, however when this does not happen we need\n  // to make sure that we include it on the rootBlocks since the first block of a fragment is always a\n  // fragment root block\n  if (blockMap.get(headKey)) {\n    rootBlocks.push(headKey);\n  }\n\n  while (rootBlock && rootBlock.getNextSiblingKey()) {\n    const lastSiblingKey = rootBlock.getNextSiblingKey();\n\n    if (!lastSiblingKey) {\n      break;\n    }\n\n    rootBlocks.push(lastSiblingKey);\n    rootBlock = blockMap.get(lastSiblingKey);\n  }\n\n  return rootBlocks;\n};\n\nconst updateBlockMapLinks = (\n  blockMap: BlockMap,\n  originalBlockMap: BlockMap,\n  targetBlock: ContentBlockNode,\n  fragmentHeadBlock: ContentBlockNode,\n): BlockMap => {\n  return blockMap.withMutations(blockMapState => {\n    const targetKey = targetBlock.getKey();\n    const headKey = fragmentHeadBlock.getKey();\n    const targetNextKey = targetBlock.getNextSiblingKey();\n    const targetParentKey = targetBlock.getParentKey();\n    const fragmentRootBlocks = getRootBlocks(fragmentHeadBlock, blockMap);\n    const lastRootFragmentBlockKey =\n      fragmentRootBlocks[fragmentRootBlocks.length - 1];\n\n    if (blockMapState.get(headKey)) {\n      // update the fragment head when it is part of the blockMap otherwise\n      blockMapState.setIn([targetKey, 'nextSibling'], headKey);\n      blockMapState.setIn([headKey, 'prevSibling'], targetKey);\n    } else {\n      // update the target block that had the fragment head contents merged into it\n      blockMapState.setIn(\n        [targetKey, 'nextSibling'],\n        fragmentHeadBlock.getNextSiblingKey(),\n      );\n      blockMapState.setIn(\n        [fragmentHeadBlock.getNextSiblingKey(), 'prevSibling'],\n        targetKey,\n      );\n    }\n\n    // update the last root block fragment\n    blockMapState.setIn(\n      [lastRootFragmentBlockKey, 'nextSibling'],\n      targetNextKey,\n    );\n\n    // update the original target next block\n    if (targetNextKey) {\n      blockMapState.setIn(\n        [targetNextKey, 'prevSibling'],\n        lastRootFragmentBlockKey,\n      );\n    }\n\n    // update fragment parent links\n    fragmentRootBlocks.forEach(blockKey =>\n      blockMapState.setIn([blockKey, 'parent'], targetParentKey),\n    );\n\n    // update targetBlock parent child links\n    if (targetParentKey) {\n      const targetParent = blockMap.get(targetParentKey);\n      const originalTargetParentChildKeys = targetParent.getChildKeys();\n\n      const targetBlockIndex = originalTargetParentChildKeys.indexOf(targetKey);\n      const insertionIndex = targetBlockIndex + 1;\n\n      const newChildrenKeysArray = originalTargetParentChildKeys.toArray();\n\n      // insert fragment children\n      newChildrenKeysArray.splice(insertionIndex, 0, ...fragmentRootBlocks);\n\n      blockMapState.setIn(\n        [targetParentKey, 'children'],\n        List(newChildrenKeysArray),\n      );\n    }\n  });\n};\n\nconst insertFragment = (\n  contentState: ContentState,\n  selectionState: SelectionState,\n  blockMap: BlockMap,\n  fragment: BlockMap,\n  targetKey: string,\n  targetOffset: number,\n): ContentState => {\n  const isTreeBasedBlockMap = blockMap.first() instanceof ContentBlockNode;\n  const newBlockArr = [];\n  const fragmentSize = fragment.size;\n  const target = blockMap.get(targetKey);\n  const head = fragment.first();\n  const tail = fragment.last();\n  const finalOffset = tail.getLength();\n  const finalKey = tail.getKey();\n  const shouldNotUpdateFromFragmentBlock =\n    isTreeBasedBlockMap &&\n    (!target.getChildKeys().isEmpty() || !head.getChildKeys().isEmpty());\n\n  blockMap.forEach((block, blockKey) => {\n    if (blockKey !== targetKey) {\n      newBlockArr.push(block);\n      return;\n    }\n\n    if (shouldNotUpdateFromFragmentBlock) {\n      newBlockArr.push(block);\n    } else {\n      newBlockArr.push(updateHead(block, targetOffset, fragment));\n    }\n\n    // Insert fragment blocks after the head and before the tail.\n    fragment\n      // when we are updating the target block with the head fragment block we skip the first fragment\n      // head since its contents have already been merged with the target block otherwise we include\n      // the whole fragment\n      .slice(shouldNotUpdateFromFragmentBlock ? 0 : 1, fragmentSize - 1)\n      .forEach(fragmentBlock => newBlockArr.push(fragmentBlock));\n\n    // update tail\n    newBlockArr.push(updateTail(block, targetOffset, fragment));\n  });\n\n  let updatedBlockMap = BlockMapBuilder.createFromArray(newBlockArr);\n\n  if (isTreeBasedBlockMap) {\n    updatedBlockMap = updateBlockMapLinks(\n      updatedBlockMap,\n      blockMap,\n      target,\n      head,\n    );\n  }\n\n  return contentState.merge({\n    blockMap: updatedBlockMap,\n    selectionBefore: selectionState,\n    selectionAfter: selectionState.merge({\n      anchorKey: finalKey,\n      anchorOffset: finalOffset,\n      focusKey: finalKey,\n      focusOffset: finalOffset,\n      isBackward: false,\n    }),\n  });\n};\n\nconst insertFragmentIntoContentState = (\n  contentState: ContentState,\n  selectionState: SelectionState,\n  fragmentBlockMap: BlockMap,\n  mergeBlockData?: BlockDataMergeBehavior = 'REPLACE_WITH_NEW_DATA',\n): ContentState => {\n  invariant(\n    selectionState.isCollapsed(),\n    '`insertFragment` should only be called with a collapsed selection state.',\n  );\n\n  const blockMap = contentState.getBlockMap();\n  const fragment = randomizeBlockMapKeys(fragmentBlockMap);\n  const targetKey = selectionState.getStartKey();\n  const targetOffset = selectionState.getStartOffset();\n\n  const targetBlock = blockMap.get(targetKey);\n\n  if (targetBlock instanceof ContentBlockNode) {\n    invariant(\n      targetBlock.getChildKeys().isEmpty(),\n      '`insertFragment` should not be called when a container node is selected.',\n    );\n  }\n\n  // When we insert a fragment with a single block we simply update the target block\n  // with the contents of the inserted fragment block\n  if (fragment.size === 1) {\n    return updateExistingBlock(\n      contentState,\n      selectionState,\n      blockMap,\n      fragment.first(),\n      targetKey,\n      targetOffset,\n      mergeBlockData,\n    );\n  }\n\n  return insertFragment(\n    contentState,\n    selectionState,\n    blockMap,\n    fragment,\n    targetKey,\n    targetOffset,\n  );\n};\n\nmodule.exports = insertFragmentIntoContentState;\n"
  },
  {
    "path": "src/model/transaction/insertIntoList.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {List} from 'immutable';\n\n/**\n * Maintain persistence for target list when appending and prepending.\n */\nfunction insertIntoList<T>(\n  targetListArg: List<T>,\n  toInsert: List<T>,\n  offset: number,\n): List<T> {\n  let targetList = targetListArg;\n  if (offset === targetList.count()) {\n    toInsert.forEach(c => {\n      targetList = targetList.push(c);\n    });\n  } else if (offset === 0) {\n    toInsert.reverse().forEach(c => {\n      targetList = targetList.unshift(c);\n    });\n  } else {\n    const head = targetList.slice(0, offset);\n    const tail = targetList.slice(offset);\n    targetList = head.concat(toInsert, tail).toList();\n  }\n  return targetList;\n}\n\nmodule.exports = insertIntoList;\n"
  },
  {
    "path": "src/model/transaction/insertTextIntoContentState.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type CharacterMetadata from 'CharacterMetadata';\nimport type ContentState from 'ContentState';\nimport type SelectionState from 'SelectionState';\n\nconst Immutable = require('immutable');\nconst insertIntoList = require('insertIntoList');\nconst invariant = require('invariant');\n\nconst {Repeat} = Immutable;\n\nfunction insertTextIntoContentState(\n  contentState: ContentState,\n  selectionState: SelectionState,\n  text: string,\n  characterMetadata: CharacterMetadata,\n): ContentState {\n  invariant(\n    selectionState.isCollapsed(),\n    '`insertText` should only be called with a collapsed range.',\n  );\n\n  let len: ?number = null;\n  if (text != null) {\n    len = text.length;\n  }\n\n  if (len == null || len === 0) {\n    return contentState;\n  }\n\n  const blockMap = contentState.getBlockMap();\n  const key = selectionState.getStartKey();\n  const offset = selectionState.getStartOffset();\n  const block = blockMap.get(key);\n  const blockText = block.getText();\n\n  const newBlock = block.merge({\n    text:\n      blockText.slice(0, offset) +\n      text +\n      blockText.slice(offset, block.getLength()),\n    characterList: insertIntoList(\n      block.getCharacterList(),\n      Repeat(characterMetadata, len).toList(),\n      offset,\n    ),\n  });\n\n  const newOffset = offset + len;\n\n  return contentState.merge({\n    blockMap: blockMap.set(key, newBlock),\n    selectionAfter: selectionState.merge({\n      anchorOffset: newOffset,\n      focusOffset: newOffset,\n    }),\n  });\n}\n\nmodule.exports = insertTextIntoContentState;\n"
  },
  {
    "path": "src/model/transaction/modifyBlockForContentState.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict-local\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type ContentState from 'ContentState';\nimport type SelectionState from 'SelectionState';\n\nconst Immutable = require('immutable');\n\nconst {Map} = Immutable;\n\nfunction modifyBlockForContentState(\n  contentState: ContentState,\n  selectionState: SelectionState,\n  operation: (block: BlockNodeRecord) => BlockNodeRecord,\n): ContentState {\n  const startKey = selectionState.getStartKey();\n  const endKey = selectionState.getEndKey();\n  const blockMap = contentState.getBlockMap();\n  const newBlocks = blockMap\n    .toSeq()\n    .skipUntil((_, k) => k === startKey)\n    .takeUntil((_, k) => k === endKey)\n    .concat(Map([[endKey, blockMap.get(endKey)]]))\n    .map(operation);\n\n  return contentState.merge({\n    blockMap: blockMap.merge(newBlocks),\n    selectionBefore: selectionState,\n    selectionAfter: selectionState,\n  });\n}\n\nmodule.exports = modifyBlockForContentState;\n"
  },
  {
    "path": "src/model/transaction/moveBlockInContentState.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockMap} from 'BlockMap';\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type ContentState from 'ContentState';\nimport type {DraftInsertionType} from 'DraftInsertionType';\n\nconst ContentBlockNode = require('ContentBlockNode');\n\nconst getNextDelimiterBlockKey = require('getNextDelimiterBlockKey');\nconst Immutable = require('immutable');\nconst invariant = require('invariant');\n\nconst {OrderedMap, List} = Immutable;\n\nconst transformBlock = (\n  key: ?string,\n  blockMap: BlockMap,\n  func: (block: ContentBlockNode) => ContentBlockNode,\n): void => {\n  if (!key) {\n    return;\n  }\n\n  const block = blockMap.get(key);\n\n  if (!block) {\n    return;\n  }\n\n  blockMap.set(key, func(block));\n};\n\nconst updateBlockMapLinks = (\n  blockMap: BlockMap,\n  originalBlockToBeMoved: BlockNodeRecord,\n  originalTargetBlock: BlockNodeRecord,\n  insertionMode: DraftInsertionType,\n  isExperimentalTreeBlock: boolean,\n): BlockMap => {\n  if (!isExperimentalTreeBlock) {\n    return blockMap;\n  }\n  // possible values of 'insertionMode' are: 'after', 'before'\n  const isInsertedAfterTarget = insertionMode === 'after';\n\n  const originalBlockKey = originalBlockToBeMoved.getKey();\n  const originalTargetKey = originalTargetBlock.getKey();\n  const originalParentKey = originalBlockToBeMoved.getParentKey();\n  const originalNextSiblingKey = originalBlockToBeMoved.getNextSiblingKey();\n  const originalPrevSiblingKey = originalBlockToBeMoved.getPrevSiblingKey();\n  const newParentKey = originalTargetBlock.getParentKey();\n  const newNextSiblingKey = isInsertedAfterTarget\n    ? originalTargetBlock.getNextSiblingKey()\n    : originalTargetKey;\n  const newPrevSiblingKey = isInsertedAfterTarget\n    ? originalTargetKey\n    : originalTargetBlock.getPrevSiblingKey();\n\n  return blockMap.withMutations(blocks => {\n    // update old parent\n    transformBlock(originalParentKey, blocks, block => {\n      const parentChildrenList = block.getChildKeys();\n      return block.merge({\n        children: parentChildrenList.delete(\n          parentChildrenList.indexOf(originalBlockKey),\n        ),\n      });\n    });\n\n    // update old prev\n    transformBlock(originalPrevSiblingKey, blocks, block =>\n      block.merge({\n        nextSibling: originalNextSiblingKey,\n      }),\n    );\n\n    // update old next\n    transformBlock(originalNextSiblingKey, blocks, block =>\n      block.merge({\n        prevSibling: originalPrevSiblingKey,\n      }),\n    );\n\n    // update new next\n    transformBlock(newNextSiblingKey, blocks, block =>\n      block.merge({\n        prevSibling: originalBlockKey,\n      }),\n    );\n\n    // update new prev\n    transformBlock(newPrevSiblingKey, blocks, block =>\n      block.merge({\n        nextSibling: originalBlockKey,\n      }),\n    );\n\n    // update new parent\n    transformBlock(newParentKey, blocks, block => {\n      const newParentChildrenList = block.getChildKeys();\n      const targetBlockIndex = newParentChildrenList.indexOf(originalTargetKey);\n\n      const insertionIndex = isInsertedAfterTarget\n        ? targetBlockIndex + 1\n        : targetBlockIndex !== 0\n        ? targetBlockIndex - 1\n        : 0;\n\n      const newChildrenArray = newParentChildrenList.toArray();\n      newChildrenArray.splice(insertionIndex, 0, originalBlockKey);\n\n      return block.merge({\n        children: List(newChildrenArray),\n      });\n    });\n\n    // update block\n    transformBlock(originalBlockKey, blocks, block =>\n      block.merge({\n        nextSibling: newNextSiblingKey,\n        prevSibling: newPrevSiblingKey,\n        parent: newParentKey,\n      }),\n    );\n  });\n};\n\nconst moveBlockInContentState = (\n  contentState: ContentState,\n  blockToBeMoved: BlockNodeRecord,\n  targetBlock: BlockNodeRecord,\n  insertionMode: DraftInsertionType,\n): ContentState => {\n  invariant(insertionMode !== 'replace', 'Replacing blocks is not supported.');\n\n  const targetKey = targetBlock.getKey();\n  const blockKey = blockToBeMoved.getKey();\n\n  invariant(blockKey !== targetKey, 'Block cannot be moved next to itself.');\n\n  const blockMap = contentState.getBlockMap();\n  const isExperimentalTreeBlock = blockToBeMoved instanceof ContentBlockNode;\n\n  let blocksToBeMoved: Array<BlockNodeRecord> = [blockToBeMoved];\n  let blockMapWithoutBlocksToBeMoved = blockMap.delete(blockKey);\n\n  if (isExperimentalTreeBlock) {\n    blocksToBeMoved = [];\n    blockMapWithoutBlocksToBeMoved = blockMap.withMutations(blocks => {\n      const nextSiblingKey = blockToBeMoved.getNextSiblingKey();\n      const nextDelimiterBlockKey = getNextDelimiterBlockKey(\n        blockToBeMoved,\n        blocks,\n      );\n\n      blocks\n        .toSeq()\n        .skipUntil(block => block.getKey() === blockKey)\n        .takeWhile(block => {\n          const key = block.getKey();\n          const isBlockToBeMoved = key === blockKey;\n          const hasNextSiblingAndIsNotNextSibling =\n            nextSiblingKey && key !== nextSiblingKey;\n          const doesNotHaveNextSiblingAndIsNotDelimiter =\n            !nextSiblingKey &&\n            block.getParentKey() &&\n            (!nextDelimiterBlockKey || key !== nextDelimiterBlockKey);\n\n          return !!(\n            isBlockToBeMoved ||\n            hasNextSiblingAndIsNotNextSibling ||\n            doesNotHaveNextSiblingAndIsNotDelimiter\n          );\n        })\n        .forEach(block => {\n          blocksToBeMoved.push(block);\n          blocks.delete(block.getKey());\n        });\n    });\n  }\n\n  const blocksBefore = blockMapWithoutBlocksToBeMoved\n    .toSeq()\n    .takeUntil(v => v === targetBlock);\n\n  const blocksAfter = blockMapWithoutBlocksToBeMoved\n    .toSeq()\n    .skipUntil(v => v === targetBlock)\n    .skip(1);\n\n  const slicedBlocks = blocksToBeMoved.map(block => [block.getKey(), block]);\n\n  let newBlocks = OrderedMap<string, BlockNodeRecord>();\n\n  if (insertionMode === 'before') {\n    const blockBefore = contentState.getBlockBefore(targetKey);\n\n    invariant(\n      !blockBefore || blockBefore.getKey() !== blockToBeMoved.getKey(),\n      'Block cannot be moved next to itself.',\n    );\n\n    newBlocks = blocksBefore\n      .concat([...slicedBlocks, [targetKey, targetBlock]], blocksAfter)\n      .toOrderedMap();\n  } else if (insertionMode === 'after') {\n    const blockAfter = contentState.getBlockAfter(targetKey);\n\n    invariant(\n      !blockAfter || blockAfter.getKey() !== blockKey,\n      'Block cannot be moved next to itself.',\n    );\n\n    newBlocks = blocksBefore\n      .concat([[targetKey, targetBlock], ...slicedBlocks], blocksAfter)\n      .toOrderedMap();\n  }\n\n  return contentState.merge({\n    blockMap: updateBlockMapLinks(\n      newBlocks,\n      blockToBeMoved,\n      targetBlock,\n      insertionMode,\n      isExperimentalTreeBlock,\n    ),\n    selectionBefore: contentState.getSelectionAfter(),\n    selectionAfter: contentState.getSelectionAfter().merge({\n      anchorKey: blockKey,\n      focusKey: blockKey,\n    }),\n  });\n};\n\nmodule.exports = moveBlockInContentState;\n"
  },
  {
    "path": "src/model/transaction/randomizeBlockMapKeys.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\nimport type {BlockMap} from 'BlockMap';\nimport type {BlockNodeKey} from 'BlockNode';\n\nconst ContentBlockNode = require('ContentBlockNode');\n\nconst generateRandomKey = require('generateRandomKey');\nconst Immutable = require('immutable');\n\nconst {OrderedMap} = Immutable;\n\nconst randomizeContentBlockNodeKeys = (blockMap: BlockMap): BlockMap => {\n  const newKeysRef: {[BlockNodeKey]: string} = {};\n\n  // we keep track of root blocks in order to update subsequent sibling links\n  let lastRootBlock: ContentBlockNode;\n\n  return OrderedMap(\n    blockMap\n      .withMutations(blockMapState => {\n        blockMapState.forEach((block, index) => {\n          const oldKey = block.getKey();\n          const nextKey = block.getNextSiblingKey();\n          const prevKey = block.getPrevSiblingKey();\n          const childrenKeys = block.getChildKeys();\n          const parentKey = block.getParentKey();\n\n          // new key that we will use to build linking\n          const key = generateRandomKey();\n\n          // we will add it here to re-use it later\n          newKeysRef[oldKey] = key;\n\n          if (nextKey) {\n            const nextBlock = blockMapState.get(nextKey);\n            if (nextBlock) {\n              blockMapState.setIn([nextKey, 'prevSibling'], key);\n            } else {\n              // this can happen when generating random keys for fragments\n              blockMapState.setIn([oldKey, 'nextSibling'], null);\n            }\n          }\n\n          if (prevKey) {\n            const prevBlock = blockMapState.get(prevKey);\n            if (prevBlock) {\n              blockMapState.setIn([prevKey, 'nextSibling'], key);\n            } else {\n              // this can happen when generating random keys for fragments\n              blockMapState.setIn([oldKey, 'prevSibling'], null);\n            }\n          }\n\n          if (parentKey && blockMapState.get(parentKey)) {\n            const parentBlock = blockMapState.get(parentKey);\n            const parentChildrenList = parentBlock.getChildKeys();\n            blockMapState.setIn(\n              [parentKey, 'children'],\n              parentChildrenList.set(\n                parentChildrenList.indexOf(block.getKey()),\n                key,\n              ),\n            );\n          } else {\n            // blocks will then be treated as root block nodes\n            blockMapState.setIn([oldKey, 'parent'], null);\n\n            if (lastRootBlock) {\n              blockMapState.setIn([lastRootBlock.getKey(), 'nextSibling'], key);\n              blockMapState.setIn(\n                [oldKey, 'prevSibling'],\n                newKeysRef[lastRootBlock.getKey()],\n              );\n            }\n\n            lastRootBlock = blockMapState.get(oldKey);\n          }\n\n          childrenKeys.forEach(childKey => {\n            const childBlock = blockMapState.get(childKey);\n            if (childBlock) {\n              blockMapState.setIn([childKey, 'parent'], key);\n            } else {\n              blockMapState.setIn(\n                [oldKey, 'children'],\n                block.getChildKeys().filter(child => child !== childKey),\n              );\n            }\n          });\n        });\n      })\n      .toArray()\n      .map(block => [\n        newKeysRef[block.getKey()],\n        block.set('key', newKeysRef[block.getKey()]),\n      ]),\n  );\n};\n\nconst randomizeContentBlockKeys = (blockMap: BlockMap): BlockMap => {\n  return OrderedMap(\n    blockMap.toArray().map(block => {\n      const key = generateRandomKey();\n      return [key, block.set('key', key)];\n    }),\n  );\n};\n\nconst randomizeBlockMapKeys = (blockMap: BlockMap): BlockMap => {\n  const isTreeBasedBlockMap = blockMap.first() instanceof ContentBlockNode;\n\n  if (!isTreeBasedBlockMap) {\n    return randomizeContentBlockKeys(blockMap);\n  }\n\n  return randomizeContentBlockNodeKeys(blockMap);\n};\n\nmodule.exports = randomizeBlockMapKeys;\n"
  },
  {
    "path": "src/model/transaction/removeEntitiesAtEdges.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type ContentState from 'ContentState';\nimport type SelectionState from 'SelectionState';\nimport type {List} from 'immutable';\n\nconst CharacterMetadata = require('CharacterMetadata');\n\nconst findRangesImmutable = require('findRangesImmutable');\nconst invariant = require('invariant');\n\nfunction removeEntitiesAtEdges(\n  contentState: ContentState,\n  selectionState: SelectionState,\n): ContentState {\n  const blockMap = contentState.getBlockMap();\n\n  const updatedBlocks: {[string]: BlockNodeRecord} = {};\n\n  const startKey = selectionState.getStartKey();\n  const startOffset = selectionState.getStartOffset();\n  const startBlock = blockMap.get(startKey);\n  const updatedStart = removeForBlock(contentState, startBlock, startOffset);\n\n  if (updatedStart !== startBlock) {\n    updatedBlocks[startKey] = updatedStart;\n  }\n\n  const endKey = selectionState.getEndKey();\n  const endOffset = selectionState.getEndOffset();\n  let endBlock = blockMap.get(endKey);\n  if (startKey === endKey) {\n    endBlock = updatedStart;\n  }\n\n  const updatedEnd = removeForBlock(contentState, endBlock, endOffset);\n\n  if (updatedEnd !== endBlock) {\n    updatedBlocks[endKey] = updatedEnd;\n  }\n\n  if (!Object.keys(updatedBlocks).length) {\n    return contentState.setSelectionAfter(selectionState);\n  }\n\n  return contentState.merge({\n    blockMap: blockMap.merge(updatedBlocks),\n    selectionAfter: selectionState,\n  });\n}\n\n/**\n * Given a list of characters and an offset that is in the middle of an entity,\n * returns the start and end of the entity that is overlapping the offset.\n * Note: This method requires that the offset be in an entity range.\n */\nfunction getRemovalRange(\n  characters: List<CharacterMetadata>,\n  entityKey: ?string,\n  offset: number,\n): {\n  start: number,\n  end: number,\n  ...\n} {\n  let removalRange;\n\n  // Iterates through a list looking for ranges of matching items\n  // based on the 'isEqual' callback.\n  // Then instead of returning the result, call the 'found' callback\n  // with each range.\n  // Then filters those ranges based on the 'filter' callback\n  //\n  // Here we use it to find ranges of characters with the same entity key.\n  findRangesImmutable(\n    characters, // the list to iterate through\n    (a, b) => a.getEntity() === b.getEntity(), // 'isEqual' callback\n    element => element.getEntity() === entityKey, // 'filter' callback\n    (start: number, end: number) => {\n      // 'found' callback\n      if (start <= offset && end >= offset) {\n        // this entity overlaps the offset index\n        removalRange = {start, end};\n      }\n    },\n  );\n  invariant(\n    typeof removalRange === 'object',\n    'Removal range must exist within character list.',\n  );\n  return removalRange;\n}\n\nfunction removeForBlock(\n  contentState: ContentState,\n  block: BlockNodeRecord,\n  offset: number,\n): BlockNodeRecord {\n  let chars = block.getCharacterList();\n  const charBefore = offset > 0 ? chars.get(offset - 1) : undefined;\n  const charAfter = offset < chars.count() ? chars.get(offset) : undefined;\n  const entityBeforeCursor = charBefore ? charBefore.getEntity() : undefined;\n  const entityAfterCursor = charAfter ? charAfter.getEntity() : undefined;\n\n  if (entityAfterCursor && entityAfterCursor === entityBeforeCursor) {\n    const entity = contentState.getEntity(entityAfterCursor);\n    if (entity.getMutability() !== 'MUTABLE') {\n      let {start, end} = getRemovalRange(chars, entityAfterCursor, offset);\n      let current;\n      while (start < end) {\n        current = chars.get(start);\n        chars = chars.set(start, CharacterMetadata.applyEntity(current, null));\n        start++;\n      }\n      return block.set('characterList', chars);\n    }\n  }\n\n  return block;\n}\n\nmodule.exports = removeEntitiesAtEdges;\n"
  },
  {
    "path": "src/model/transaction/removeRangeFromContentState.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockMap} from 'BlockMap';\nimport type {BlockNodeRecord} from 'BlockNodeRecord';\nimport type CharacterMetadata from 'CharacterMetadata';\nimport type ContentBlock from 'ContentBlock';\nimport type ContentState from 'ContentState';\nimport type SelectionState from 'SelectionState';\n\nconst ContentBlockNode = require('ContentBlockNode');\n\nconst getNextDelimiterBlockKey = require('getNextDelimiterBlockKey');\nconst Immutable = require('immutable');\n\nconst {List, Map} = Immutable;\n\nconst transformBlock = (\n  key: ?string,\n  blockMap: BlockMap,\n  func: (block: ContentBlockNode) => ContentBlockNode,\n): void => {\n  if (!key) {\n    return;\n  }\n\n  const block = blockMap.get(key);\n\n  if (!block) {\n    return;\n  }\n\n  blockMap.set(key, func(block));\n};\n\n/**\n * Ancestors needs to be preserved when there are non selected\n * children to make sure we do not leave any orphans behind\n */\nconst getAncestorsKeys = (\n  blockKey: ?string,\n  blockMap: BlockMap,\n): Array<string> => {\n  const parents = [];\n\n  if (!blockKey) {\n    return parents;\n  }\n\n  let blockNode: ?(BlockNodeRecord | ContentBlock | ContentBlockNode) =\n    blockMap.get(blockKey);\n  while (blockNode && blockNode.getParentKey()) {\n    const parentKey = blockNode.getParentKey();\n    if (parentKey) {\n      parents.push(parentKey);\n    }\n    blockNode = parentKey ? blockMap.get(parentKey) : null;\n  }\n\n  return parents;\n};\n\n/**\n * Get all next delimiter keys until we hit a root delimiter and return\n * an array of key references\n */\nconst getNextDelimitersBlockKeys = (\n  block: ContentBlockNode,\n  blockMap: BlockMap,\n): Array<string> => {\n  const nextDelimiters = [];\n\n  if (!block) {\n    return nextDelimiters;\n  }\n\n  let nextDelimiter = getNextDelimiterBlockKey(block, blockMap);\n  while (nextDelimiter && blockMap.get(nextDelimiter)) {\n    const block = blockMap.get(nextDelimiter);\n    nextDelimiters.push(nextDelimiter);\n\n    // we do not need to keep checking all root node siblings, just the first occurance\n    nextDelimiter = block.getParentKey()\n      ? getNextDelimiterBlockKey(block, blockMap)\n      : null;\n  }\n\n  return nextDelimiters;\n};\n\nconst getNextValidSibling = (\n  block: ?ContentBlockNode,\n  blockMap: BlockMap,\n  originalBlockMap: BlockMap,\n): ?string => {\n  if (!block) {\n    return null;\n  }\n\n  // note that we need to make sure we refer to the original block since this\n  // function is called within a withMutations\n  let nextValidSiblingKey = originalBlockMap\n    .get(block.getKey())\n    .getNextSiblingKey();\n\n  while (nextValidSiblingKey && !blockMap.get(nextValidSiblingKey)) {\n    nextValidSiblingKey =\n      originalBlockMap.get(nextValidSiblingKey).getNextSiblingKey() || null;\n  }\n\n  return nextValidSiblingKey;\n};\n\nconst getPrevValidSibling = (\n  block: ?ContentBlockNode,\n  blockMap: BlockMap,\n  originalBlockMap: BlockMap,\n): ?string => {\n  if (!block) {\n    return null;\n  }\n\n  // note that we need to make sure we refer to the original block since this\n  // function is called within a withMutations\n  let prevValidSiblingKey = originalBlockMap\n    .get(block.getKey())\n    .getPrevSiblingKey();\n\n  while (prevValidSiblingKey && !blockMap.get(prevValidSiblingKey)) {\n    prevValidSiblingKey =\n      originalBlockMap.get(prevValidSiblingKey).getPrevSiblingKey() || null;\n  }\n\n  return prevValidSiblingKey;\n};\n\nconst updateBlockMapLinks = (\n  blockMap: BlockMap,\n  startBlock: ContentBlockNode,\n  endBlock: ContentBlockNode,\n  originalBlockMap: BlockMap,\n): BlockMap => {\n  return blockMap.withMutations(blocks => {\n    // update start block if its retained\n    transformBlock(startBlock.getKey(), blocks, block =>\n      block.merge({\n        nextSibling: getNextValidSibling(block, blocks, originalBlockMap),\n        prevSibling: getPrevValidSibling(block, blocks, originalBlockMap),\n      }),\n    );\n\n    // update endblock if its retained\n    transformBlock(endBlock.getKey(), blocks, block =>\n      block.merge({\n        nextSibling: getNextValidSibling(block, blocks, originalBlockMap),\n        prevSibling: getPrevValidSibling(block, blocks, originalBlockMap),\n      }),\n    );\n\n    // update start block parent ancestors\n    getAncestorsKeys(startBlock.getKey(), originalBlockMap).forEach(parentKey =>\n      transformBlock(parentKey, blocks, block =>\n        block.merge({\n          children: block.getChildKeys().filter(key => blocks.get(key)),\n          nextSibling: getNextValidSibling(block, blocks, originalBlockMap),\n          prevSibling: getPrevValidSibling(block, blocks, originalBlockMap),\n        }),\n      ),\n    );\n\n    // update start block next - can only happen if startBlock == endBlock\n    transformBlock(startBlock.getNextSiblingKey(), blocks, block =>\n      block.merge({\n        prevSibling: startBlock.getPrevSiblingKey(),\n      }),\n    );\n\n    // update start block prev\n    transformBlock(startBlock.getPrevSiblingKey(), blocks, block =>\n      block.merge({\n        nextSibling: getNextValidSibling(block, blocks, originalBlockMap),\n      }),\n    );\n\n    // update end block next\n    transformBlock(endBlock.getNextSiblingKey(), blocks, block =>\n      block.merge({\n        prevSibling: getPrevValidSibling(block, blocks, originalBlockMap),\n      }),\n    );\n\n    // update end block prev\n    transformBlock(endBlock.getPrevSiblingKey(), blocks, block =>\n      block.merge({\n        nextSibling: endBlock.getNextSiblingKey(),\n      }),\n    );\n\n    // update end block parent ancestors\n    getAncestorsKeys(endBlock.getKey(), originalBlockMap).forEach(parentKey => {\n      transformBlock(parentKey, blocks, block =>\n        block.merge({\n          children: block.getChildKeys().filter(key => blocks.get(key)),\n          nextSibling: getNextValidSibling(block, blocks, originalBlockMap),\n          prevSibling: getPrevValidSibling(block, blocks, originalBlockMap),\n        }),\n      );\n    });\n\n    // update next delimiters all the way to a root delimiter\n    getNextDelimitersBlockKeys(endBlock, originalBlockMap).forEach(\n      delimiterKey =>\n        transformBlock(delimiterKey, blocks, block =>\n          block.merge({\n            nextSibling: getNextValidSibling(block, blocks, originalBlockMap),\n            prevSibling: getPrevValidSibling(block, blocks, originalBlockMap),\n          }),\n        ),\n    );\n\n    // if parent (startBlock) was deleted\n    if (\n      blockMap.get(startBlock.getKey()) == null &&\n      blockMap.get(endBlock.getKey()) != null &&\n      endBlock.getParentKey() === startBlock.getKey() &&\n      endBlock.getPrevSiblingKey() == null\n    ) {\n      const prevSiblingKey = startBlock.getPrevSiblingKey();\n      // endBlock becomes next sibling of parent's prevSibling\n      transformBlock(endBlock.getKey(), blocks, block =>\n        block.merge({\n          prevSibling: prevSiblingKey,\n        }),\n      );\n      transformBlock(prevSiblingKey, blocks, block =>\n        block.merge({\n          nextSibling: endBlock.getKey(),\n        }),\n      );\n\n      // Update parent for previous parent's children, and children for that parent\n      const prevSibling = prevSiblingKey ? blockMap.get(prevSiblingKey) : null;\n      const newParentKey = prevSibling ? prevSibling.getParentKey() : null;\n      startBlock.getChildKeys().forEach(childKey => {\n        transformBlock(childKey, blocks, block =>\n          block.merge({\n            parent: newParentKey, // set to null if there is no parent\n          }),\n        );\n      });\n      if (newParentKey != null) {\n        const newParent = blockMap.get(newParentKey);\n        transformBlock(newParentKey, blocks, block =>\n          block.merge({\n            children: newParent\n              .getChildKeys()\n              .concat(startBlock.getChildKeys()),\n          }),\n        );\n      }\n\n      // last child of deleted parent should point to next sibling\n      transformBlock(\n        startBlock.getChildKeys().find(key => {\n          const block = (blockMap.get(key): ContentBlockNode);\n          return block.getNextSiblingKey() === null;\n        }),\n        blocks,\n        block =>\n          block.merge({\n            nextSibling: startBlock.getNextSiblingKey(),\n          }),\n      );\n    }\n  });\n};\n\nconst removeRangeFromContentState = (\n  contentState: ContentState,\n  selectionState: SelectionState,\n): ContentState => {\n  if (selectionState.isCollapsed()) {\n    return contentState;\n  }\n\n  const blockMap = contentState.getBlockMap();\n  const startKey = selectionState.getStartKey();\n  const startOffset = selectionState.getStartOffset();\n  const endKey = selectionState.getEndKey();\n  const endOffset = selectionState.getEndOffset();\n\n  const startBlock = blockMap.get(startKey);\n  const endBlock = blockMap.get(endKey);\n\n  // we assume that ContentBlockNode and ContentBlocks are not mixed together\n  const isExperimentalTreeBlock = startBlock instanceof ContentBlockNode;\n\n  // used to retain blocks that should not be deleted to avoid orphan children\n  let parentAncestors: Array<string> = [];\n\n  if (isExperimentalTreeBlock) {\n    const endBlockchildrenKeys = endBlock.getChildKeys();\n    const endBlockAncestors = getAncestorsKeys(endKey, blockMap);\n\n    // endBlock has unselected siblings so we can not remove its ancestors parents\n    if (endBlock.getNextSiblingKey()) {\n      parentAncestors = parentAncestors.concat(endBlockAncestors);\n    }\n\n    // endBlock has children so can not remove this block or any of its ancestors\n    if (!endBlockchildrenKeys.isEmpty()) {\n      parentAncestors = parentAncestors.concat(\n        endBlockAncestors.concat([endKey]),\n      );\n    }\n\n    // we need to retain all ancestors of the next delimiter block\n    parentAncestors = parentAncestors.concat(\n      getAncestorsKeys(getNextDelimiterBlockKey(endBlock, blockMap), blockMap),\n    );\n  }\n\n  let characterList;\n\n  if (startBlock === endBlock) {\n    characterList = removeFromList(\n      startBlock.getCharacterList(),\n      startOffset,\n      endOffset,\n    );\n  } else {\n    characterList = startBlock\n      .getCharacterList()\n      .slice(0, startOffset)\n      .concat(endBlock.getCharacterList().slice(endOffset));\n  }\n\n  const modifiedStart = startBlock.merge({\n    text:\n      startBlock.getText().slice(0, startOffset) +\n      endBlock.getText().slice(endOffset),\n    characterList,\n  });\n\n  // If cursor (collapsed) is at the start of the first child, delete parent\n  // instead of child\n  const shouldDeleteParent =\n    isExperimentalTreeBlock &&\n    startOffset === 0 &&\n    endOffset === 0 &&\n    endBlock.getParentKey() === startKey &&\n    endBlock.getPrevSiblingKey() == null;\n  const newBlocks = shouldDeleteParent\n    ? Map([[startKey, null]])\n    : blockMap\n        .toSeq()\n        .skipUntil((_, k) => k === startKey)\n        .takeUntil((_, k) => k === endKey)\n        .filter((_, k) => parentAncestors.indexOf(k) === -1)\n        .concat(Map([[endKey, null]]))\n        .map((_, k) => {\n          return k === startKey ? modifiedStart : null;\n        });\n  // $FlowFixMe[incompatible-call] added when improving typing for this parameters\n  let updatedBlockMap = blockMap.merge(newBlocks).filter(block => !!block);\n\n  // Only update tree block pointers if the range is across blocks\n  if (isExperimentalTreeBlock && startBlock !== endBlock) {\n    updatedBlockMap = updateBlockMapLinks(\n      updatedBlockMap,\n      startBlock,\n      endBlock,\n      blockMap,\n    );\n  }\n\n  return contentState.merge({\n    blockMap: updatedBlockMap,\n    selectionBefore: selectionState,\n    selectionAfter: selectionState.merge({\n      anchorKey: startKey,\n      anchorOffset: startOffset,\n      focusKey: startKey,\n      focusOffset: startOffset,\n      isBackward: false,\n    }),\n  });\n};\n\n/**\n * Maintain persistence for target list when removing characters on the\n * head and tail of the character list.\n */\nconst removeFromList = (\n  targetList: List<CharacterMetadata>,\n  startOffset: number,\n  endOffset: number,\n): List<CharacterMetadata> => {\n  if (startOffset === 0) {\n    while (startOffset < endOffset) {\n      targetList = targetList.shift();\n      startOffset++;\n    }\n  } else if (endOffset === targetList.count()) {\n    while (endOffset > startOffset) {\n      targetList = targetList.pop();\n      endOffset--;\n    }\n  } else {\n    const head = targetList.slice(0, startOffset);\n    const tail = targetList.slice(endOffset);\n    targetList = head.concat(tail).toList();\n  }\n  return targetList;\n};\n\nmodule.exports = removeRangeFromContentState;\n"
  },
  {
    "path": "src/model/transaction/splitBlockInContentState.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n * @oncall draft_js\n */\n\n'use strict';\n\nimport type {BlockMap} from 'BlockMap';\nimport type ContentState from 'ContentState';\nimport type SelectionState from 'SelectionState';\n\nconst ContentBlockNode = require('ContentBlockNode');\n\nconst generateRandomKey = require('generateRandomKey');\nconst Immutable = require('immutable');\nconst invariant = require('invariant');\nconst modifyBlockForContentState = require('modifyBlockForContentState');\n\nconst {List, Map} = Immutable;\n\nconst transformBlock = (\n  key: ?string,\n  blockMap: BlockMap,\n  func: (block: ContentBlockNode) => ContentBlockNode,\n): void => {\n  if (!key) {\n    return;\n  }\n\n  const block = blockMap.get(key);\n\n  if (!block) {\n    return;\n  }\n\n  blockMap.set(key, func(block));\n};\n\nconst updateBlockMapLinks = (\n  blockMap: BlockMap,\n  originalBlock: ContentBlockNode,\n  belowBlock: ContentBlockNode,\n): BlockMap => {\n  return blockMap.withMutations(blocks => {\n    const originalBlockKey = originalBlock.getKey();\n    const belowBlockKey = belowBlock.getKey();\n\n    // update block parent\n    transformBlock(originalBlock.getParentKey(), blocks, block => {\n      const parentChildrenList = block.getChildKeys();\n      const insertionIndex = parentChildrenList.indexOf(originalBlockKey) + 1;\n      const newChildrenArray = parentChildrenList.toArray();\n\n      newChildrenArray.splice(insertionIndex, 0, belowBlockKey);\n\n      return block.merge({\n        children: List(newChildrenArray),\n      });\n    });\n\n    // update original next block\n    transformBlock(originalBlock.getNextSiblingKey(), blocks, block =>\n      block.merge({\n        prevSibling: belowBlockKey,\n      }),\n    );\n\n    // update original block\n    transformBlock(originalBlockKey, blocks, block =>\n      block.merge({\n        nextSibling: belowBlockKey,\n      }),\n    );\n\n    // update below block\n    transformBlock(belowBlockKey, blocks, block =>\n      block.merge({\n        prevSibling: originalBlockKey,\n      }),\n    );\n  });\n};\n\nconst splitBlockInContentState = (\n  contentState: ContentState,\n  selectionState: SelectionState,\n): ContentState => {\n  invariant(selectionState.isCollapsed(), 'Selection range must be collapsed.');\n\n  const key = selectionState.getAnchorKey();\n  const blockMap = contentState.getBlockMap();\n  const blockToSplit = blockMap.get(key);\n  const text = blockToSplit.getText();\n\n  if (!text) {\n    const blockType = blockToSplit.getType();\n    if (\n      blockType === 'unordered-list-item' ||\n      blockType === 'ordered-list-item'\n    ) {\n      return modifyBlockForContentState(contentState, selectionState, block =>\n        block.merge({type: 'unstyled', depth: 0}),\n      );\n    }\n  }\n\n  const offset = selectionState.getAnchorOffset();\n  const chars = blockToSplit.getCharacterList();\n  const keyBelow = generateRandomKey();\n  const isExperimentalTreeBlock = blockToSplit instanceof ContentBlockNode;\n\n  const blockAbove = blockToSplit.merge({\n    text: text.slice(0, offset),\n    characterList: chars.slice(0, offset),\n  });\n  const blockBelow = blockAbove.merge({\n    key: keyBelow,\n    text: text.slice(offset),\n    characterList: chars.slice(offset),\n    data: Map(),\n  });\n\n  const blocksBefore = blockMap.toSeq().takeUntil(v => v === blockToSplit);\n  const blocksAfter = blockMap\n    .toSeq()\n    .skipUntil(v => v === blockToSplit)\n    .rest();\n  let newBlocks = blocksBefore\n    .concat(\n      [\n        [key, blockAbove],\n        [keyBelow, blockBelow],\n      ],\n      blocksAfter,\n    )\n    .toOrderedMap();\n\n  if (isExperimentalTreeBlock) {\n    invariant(\n      blockToSplit.getChildKeys().isEmpty(),\n      'ContentBlockNode must not have children',\n    );\n\n    newBlocks = updateBlockMapLinks(newBlocks, blockAbove, blockBelow);\n  }\n\n  return contentState.merge({\n    blockMap: newBlocks,\n    selectionBefore: selectionState,\n    selectionAfter: selectionState.merge({\n      anchorKey: keyBelow,\n      anchorOffset: 0,\n      focusKey: keyBelow,\n      focusOffset: 0,\n      isBackward: false,\n    }),\n  });\n};\n\nmodule.exports = splitBlockInContentState;\n"
  },
  {
    "path": "src/stubs/ComposedEntityMutability.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n */\n\n'use strict';\n\nvar ComposedEntityMutability = {\n  MUTABLE: true,\n  IMMUTABLE: true,\n  SEGMENTED: true,\n};\n\nmodule.exports = ComposedEntityMutability;\n"
  },
  {
    "path": "src/stubs/DraftEditorContents.react.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n * @format\n */\n\n'use strict';\n\nconst gkx = require('gkx');\n\nconst experimentalTreeDataSupport = gkx('draft_tree_data_support');\n\nmodule.exports = experimentalTreeDataSupport\n  ? require('DraftEditorContentsExperimental.react')\n  : require('DraftEditorContents-core.react');\n"
  },
  {
    "path": "src/stubs/DraftEffects.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n'use strict';\n\nmodule.exports = {\n  initODS: function() {},\n  handleExtensionCausedError: function() {},\n};\n"
  },
  {
    "path": "src/stubs/DraftJsDebugLogging.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n'use strict';\n\nmodule.exports = {\n  logBlockedSelectionEvent: () => null,\n  logSelectionStateFailure: () => null,\n};\n"
  },
  {
    "path": "src/stubs/gkx.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow strict\n * @format\n */\n\n'use strict';\n\nmodule.exports = function (name: string) {\n  if (typeof window !== 'undefined' && window.__DRAFT_GKX) {\n    return !!window.__DRAFT_GKX[name];\n  }\n  return false;\n};\n"
  },
  {
    "path": "src/util/getOwnObjectValues.js",
    "content": "/**\n * (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.\n *\n * @flow strict\n * @format\n * @typechecks\n */\n\n/**\n * Retrieve an object's own values as an array. If you want the values in the\n * protoype chain, too, use getObjectValuesIncludingPrototype.\n *\n * If you are looking for a function that creates an Array instance based\n * on an \"Array-like\" object, use createArrayFrom instead.\n *\n * @param {object} obj An object.\n * @return {array}     The object's values.\n */\nfunction getOwnObjectValues<TValue>(obj: {\n  +[key: string]: TValue,\n  ...\n}): Array<TValue> {\n  return Object.keys(obj).map(key => obj[key]);\n}\n\nmodule.exports = getOwnObjectValues;\n"
  },
  {
    "path": "src/util/uuid.js",
    "content": "/**\n * (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.\n *\n * @flow strict\n * @format\n * @typechecks\n */\n\n/*eslint-disable no-bitwise */\n\n/**\n * Based on the rfc4122-compliant solution posted at\n * http://stackoverflow.com/questions/105034\n */\nfunction uuid(): string {\n  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {\n    const r = (Math.random() * 16) | 0;\n    const v = c == 'x' ? r : (r & 0x3) | 0x8;\n    return v.toString(16);\n  });\n}\n\nmodule.exports = uuid;\n"
  },
  {
    "path": "website/.gitignore",
    "content": "# Dependencies\nnode_modules\n\n# Production\nbuild\n\n# Generated files\n.docusaurus\n.cache-loader\n\n# Misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\n# Logs\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "website/README.md",
    "content": "# Draft.js website\n\nThis website is built using [Docusaurus 2](https://v2.docusaurus.io/), a modern static website generator.\n\n### Installation\n\n```\n$ yarn\n```\n\n### Local Development\n\n```\n$ yarn start\n```\n\nThis command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server.\n\n### Formatting Docs\n\nIf you have changed any documentation, before submitting your PR, please run the following command from the root of the directory to use Prettier to format the documentation.\n\n```\n$ yarn format-docs\n```\n\n### Build\n\n```\n$ yarn build\n```\n\nThis command generates static content into the `build` directory and can be served using any static contents hosting service.\n\n### Deployment\n\n```\n$ GIT_USER=<Your GitHub username> USE_SSH=true yarn deploy\n```\n\nIf you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.\n"
  },
  {
    "path": "website/docusaurus.config.js",
    "content": "const {\n  fbInternalOnly\n} = require('internaldocs-fb-helpers');\n\n/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\nmodule.exports = {\n  title: 'Draft.js',\n  tagline: 'Rich Text Editor Framework for React',\n  url: 'https://draftjs.org',\n  baseUrl: '/',\n  organizationName: 'facebook',\n  projectName: 'draft-js',\n  favicon: 'img/draftjs-logo.ico',\n  presets: [['@docusaurus/preset-classic', {\n    docs: {\n      path: '../docs',\n      sidebarPath: require.resolve('./sidebars.js'),\n      editUrl: 'https://github.com/facebook/draft-js/edit/master/docs',\n      showLastUpdateAuthor: true,\n      showLastUpdateTime: true\n    },\n    theme: {\n      customCss: require.resolve('./src/css/custom.css')\n    }\n  }]],\n  themeConfig: {\n    disableDarkMode: true,\n    announcementBar: {\n      id: 'support_ukraine',\n      content:\n        'Support Ukraine 🇺🇦 <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://opensource.facebook.com/support-ukraine\"> Help Provide Humanitarian Aid to Ukraine</a>.',\n      backgroundColor: '#20232a',\n      textColor: '#fff',\n      isCloseable: false,\n    },\n    navbar: {\n      title: 'Draft.js',\n      logo: {\n        alt: 'Draft.js Logo',\n        src: 'img/draftjs-logo.svg'\n      },\n      links: [{\n        to: 'docs/getting-started',\n        label: 'Docs',\n        position: 'right'\n      }, {\n        href: 'https://github.com/facebook/draft-js',\n        label: 'GitHub',\n        position: 'right'\n      }, ...fbInternalOnly([{\n        \"to\": \"docs/fb/index\",\n        \"label\": \"FB Internal\",\n        \"position\": \"right\"\n      }])]\n    },\n    algolia: {\n      apiKey: 'ae94c9e3ee00ea8edddd484adafc37cd',\n      indexName: 'draft-js'\n    },\n    googleAnalytics: {\n      trackingID: 'UA-44373548-19'\n    },\n    footer: {\n      style: 'dark',\n      links: [{\n        title: 'Docs',\n        items: [{\n          label: 'Getting Started',\n          to: 'docs/getting-started'\n        }, {\n          label: 'API Reference',\n          to: 'docs/api-reference-editor'\n        }]\n      }, {\n        title: 'Community',\n        items: [{\n          label: 'Stack Overflow',\n          href: 'https://stackoverflow.com/questions/tagged/draftjs'\n        }, {\n          label: 'Twitter',\n          href: 'https://twitter.com/draft_js'\n        }]\n      }, {\n        title: 'More',\n        items: [{\n          label: 'GitHub',\n          href: 'https://github.com/facebook/draft-js'\n        }]\n      }],\n      logo: {\n        alt: 'Facebook Open Source Logo',\n        src: '/img/oss_logo.png',\n        href: 'https://opensource.facebook.com/'\n      },\n      copyright: `Copyright © ${new Date().getFullYear()} Facebook, Inc.`\n    }\n  },\n  plugins: [require.resolve('docusaurus-plugin-internaldocs-fb')],\n};\n"
  },
  {
    "path": "website/package.json",
    "content": "{\n  \"scripts\": {\n    \"start\": \"docusaurus start\",\n    \"build\": \"docusaurus build\",\n    \"swizzle\": \"docusaurus swizzle\",\n    \"deploy\": \"docusaurus deploy\"\n  },\n  \"dependencies\": {\n    \"@docusaurus/core\": \"^2.0.0-alpha.48\",\n    \"@docusaurus/preset-classic\": \"^2.0.0-alpha.48\",\n    \"classnames\": \"^2.2.6\",\n    \"docusaurus-plugin-internaldocs-fb\": \"^0.5.2\",\n    \"draft-js\": \"0.11.5\",\n    \"internaldocs-fb-helpers\": \"^1.1.0\",\n    \"react\": \"^16.10.2\",\n    \"react-dom\": \"^16.10.2\"\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.2%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  }\n}\n"
  },
  {
    "path": "website/sidebars.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nconst {fbInternalOnly} = require('internaldocs-fb-helpers');\n\nmodule.exports = {\n  docs: {\n    'Quick Start': [\n      'getting-started',\n      'quickstart-api-basics',\n      'quickstart-rich-styling',\n    ],\n    'Advanced Topics': [\n      'advanced-topics-entities',\n      'v0-10-api-migration',\n      'advanced-topics-decorators',\n      'advanced-topics-key-bindings',\n      'advanced-topics-managing-focus',\n      'advanced-topics-block-styling',\n      'advanced-topics-custom-block-render-map',\n      'advanced-topics-block-components',\n      'advanced-topics-inline-styles',\n      'advanced-topics-nested-lists',\n      'advanced-topics-text-direction',\n      'advanced-topics-editorstate-race-conditions',\n      'advanced-topics-issues-and-pitfalls',\n    ],\n    'API Reference': [\n      'api-reference-editor',\n      'api-reference-editor-change-type',\n      'api-reference-editor-state',\n      'api-reference-content-state',\n      'api-reference-content-block',\n      'api-reference-character-metadata',\n      'api-reference-entity',\n      'api-reference-selection-state',\n      'api-reference-composite-decorator',\n      'api-reference-data-conversion',\n      'api-reference-rich-utils',\n      'api-reference-atomic-block-utils',\n      'api-reference-key-binding-util',\n      'api-reference-modifier',\n    ],\n  },\n  'fb-internal': {\n    'FB Internal': fbInternalOnly([\n      'fb/draft-js-g-ks',\n      'fb/github-code-sync',\n      'fb/impact-of-draft-js',\n      'fb/importing-p-rs',\n      'fb/internal-manual-test-plan',\n      'fb/internal-tools-teams-using-draft-js',\n      'fb/migrating-from-draft-0-9-1-to-0-10-0',\n      'fb/oncall',\n      'fb/opening-a-pull-request',\n      'fb/releasing-a-new-version',\n      'fb/triaging-issues',\n      'fb/index',\n    ]),\n  },\n};\n"
  },
  {
    "path": "website/src/components/DraftEditorExample/css/draft.css",
    "content": "/**\n * Draft v0.11.3\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n.DraftEditor-editorContainer,.DraftEditor-root,.public-DraftEditor-content{height:inherit;text-align:initial}.public-DraftEditor-content[contenteditable=true]{-webkit-user-modify:read-write-plaintext-only}.DraftEditor-root{position:relative}.DraftEditor-editorContainer{background-color:rgba(255,255,255,0);border-left:.1px solid transparent;position:relative;z-index:1}.public-DraftEditor-block{position:relative}.DraftEditor-alignLeft .public-DraftStyleDefault-block{text-align:left}.DraftEditor-alignLeft .public-DraftEditorPlaceholder-root{left:0;text-align:left}.DraftEditor-alignCenter .public-DraftStyleDefault-block{text-align:center}.DraftEditor-alignCenter .public-DraftEditorPlaceholder-root{margin:0 auto;text-align:center;width:100%}.DraftEditor-alignRight .public-DraftStyleDefault-block{text-align:right}.DraftEditor-alignRight .public-DraftEditorPlaceholder-root{right:0;text-align:right}.public-DraftEditorPlaceholder-root{color:#9197a3;position:absolute;z-index:1}.public-DraftEditorPlaceholder-hasFocus{color:#bdc1c9}.DraftEditorPlaceholder-hidden{display:none}.public-DraftStyleDefault-block{position:relative;white-space:pre-wrap}.public-DraftStyleDefault-ltr{direction:ltr;text-align:left}.public-DraftStyleDefault-rtl{direction:rtl;text-align:right}.public-DraftStyleDefault-listLTR{direction:ltr}.public-DraftStyleDefault-listRTL{direction:rtl}.public-DraftStyleDefault-ol,.public-DraftStyleDefault-ul{margin:16px 0;padding:0}.public-DraftStyleDefault-depth0.public-DraftStyleDefault-listLTR{margin-left:1.5em}.public-DraftStyleDefault-depth0.public-DraftStyleDefault-listRTL{margin-right:1.5em}.public-DraftStyleDefault-depth1.public-DraftStyleDefault-listLTR{margin-left:3em}.public-DraftStyleDefault-depth1.public-DraftStyleDefault-listRTL{margin-right:3em}.public-DraftStyleDefault-depth2.public-DraftStyleDefault-listLTR{margin-left:4.5em}.public-DraftStyleDefault-depth2.public-DraftStyleDefault-listRTL{margin-right:4.5em}.public-DraftStyleDefault-depth3.public-DraftStyleDefault-listLTR{margin-left:6em}.public-DraftStyleDefault-depth3.public-DraftStyleDefault-listRTL{margin-right:6em}.public-DraftStyleDefault-depth4.public-DraftStyleDefault-listLTR{margin-left:7.5em}.public-DraftStyleDefault-depth4.public-DraftStyleDefault-listRTL{margin-right:7.5em}.public-DraftStyleDefault-unorderedListItem{list-style-type:square;position:relative}.public-DraftStyleDefault-unorderedListItem.public-DraftStyleDefault-depth0{list-style-type:disc}.public-DraftStyleDefault-unorderedListItem.public-DraftStyleDefault-depth1{list-style-type:circle}.public-DraftStyleDefault-orderedListItem{list-style-type:none;position:relative}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-listLTR:before{left:-36px;position:absolute;text-align:right;width:30px}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-listRTL:before{position:absolute;right:-36px;text-align:left;width:30px}.public-DraftStyleDefault-orderedListItem:before{content:counter(ol0) \". \";counter-increment:ol0}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-depth1:before{content:counter(ol1,lower-alpha) \". \";counter-increment:ol1}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-depth2:before{content:counter(ol2,lower-roman) \". \";counter-increment:ol2}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-depth3:before{content:counter(ol3) \". \";counter-increment:ol3}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-depth4:before{content:counter(ol4,lower-alpha) \". \";counter-increment:ol4}.public-DraftStyleDefault-depth0.public-DraftStyleDefault-reset{counter-reset:ol0}.public-DraftStyleDefault-depth1.public-DraftStyleDefault-reset{counter-reset:ol1}.public-DraftStyleDefault-depth2.public-DraftStyleDefault-reset{counter-reset:ol2}.public-DraftStyleDefault-depth3.public-DraftStyleDefault-reset{counter-reset:ol3}.public-DraftStyleDefault-depth4.public-DraftStyleDefault-reset{counter-reset:ol4}\n"
  },
  {
    "path": "website/src/components/DraftEditorExample/css/example.css",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n#rich-example em {\n  font-style: italic;\n}\n\n#rich-example h1,\n#rich-example h2,\n#rich-example h3,\n#rich-example h4,\n#rich-example h5,\n#rich-example h6 {\n  margin: 10px 0;\n  font-family: inherit;\n  font-weight: bold;\n  line-height: 20px;\n  color: inherit;\n  text-rendering: optimizelegibility;\n}\n\n#rich-example h1 small,\n#rich-example h2 small,\n#rich-example h3 small,\n#rich-example h4 small,\n#rich-example h5 small,\n#rich-example h6 small {\n  font-weight: normal;\n  color: #7b7b7b;\n}\n\n#rich-example h1,\n#rich-example h2,\n#rich-example h3 {\n  line-height: 40px;\n}\n\n#rich-example h1 {\n  font-size: 39px;\n}\n\n#rich-example h2 {\n  font-size: 31px;\n}\n\n#rich-example h3 {\n  font-size: 23px;\n}\n\n#rich-example h4 {\n  font-size: 17px;\n}\n\n#rich-example h5 {\n  font-size: 14px;\n}\n\n#rich-example h6 {\n  font-size: 11px;\n}\n\n#rich-example h1 small {\n  font-size: 24px;\n}\n\n#rich-example h2 small {\n  font-size: 18px;\n}\n\n#rich-example h3 small {\n  font-size: 16px;\n}\n\n#rich-example h4 small {\n  font-size: 14px;\n}\n\n#rich-example ul, #rich-example ol {\n  margin: 0 0 10px 25px;\n  padding: 0;\n}\n\n#rich-example ul ul,\n#rich-example ul ol,\n#rich-example ol ol,\n#rich-example ol ul {\n  margin-bottom: 0;\n}\n\n#rich-example li {\n  line-height: 20px;\n}\n\n#rich-example blockquote {\n  background-color: inherit;\n}\n"
  },
  {
    "path": "website/src/components/DraftEditorExample/css/rich-editor.css",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n.RichEditor-root {\n  background: #fff;\n  border: 1px solid #ddd;\n  font-family: 'Georgia', serif;\n  font-size: 14px;\n  padding: 15px;\n}\n\n.RichEditor-editor {\n  border-top: 1px solid #ddd;\n  cursor: text;\n  font-size: 16px;\n  margin-top: 10px;\n}\n\n.RichEditor-editor .public-DraftEditorPlaceholder-root,\n.RichEditor-editor .public-DraftEditor-content {\n  margin: 0 -15px -15px;\n  padding: 15px;\n}\n\n.RichEditor-editor .public-DraftEditor-content {\n  min-height: 100px;\n}\n\n.RichEditor-hidePlaceholder .public-DraftEditorPlaceholder-root {\n  display: none;\n}\n\n.RichEditor-editor .RichEditor-blockquote {\n  border-left: 5px solid #eee;\n  color: #666;\n  font-family: 'Hoefler Text', 'Georgia', serif;\n  font-style: italic;\n  margin: 16px 0;\n  padding: 10px 20px;\n}\n\n.RichEditor-editor .public-DraftStyleDefault-pre {\n  background-color: rgba(0, 0, 0, 0.05);\n  font-family: 'Inconsolata', 'Menlo', 'Consolas', monospace;\n  font-size: 16px;\n  padding: 20px;\n}\n\n.RichEditor-controls {\n  font-family: 'Helvetica', sans-serif;\n  font-size: 14px;\n  margin-bottom: 5px;\n  user-select: none;\n}\n\n.RichEditor-styleButton {\n  color: #999;\n  cursor: pointer;\n  margin-right: 16px;\n  padding: 2px 0;\n  display: inline-block;\n}\n\n.RichEditor-activeButton {\n  color: #5890ff;\n}\n"
  },
  {
    "path": "website/src/components/DraftEditorExample/index.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport React from 'react';\nimport {Editor, EditorState, RichUtils, getDefaultKeyBinding} from 'draft-js';\n\nimport './css/example.css';\nimport './css/draft.css';\nimport './css/rich-editor.css';\n\nconst {useState, useRef, useCallback} = React;\n\nfunction RichEditorExample(props) {\n  const [editorState, setEditorState] = useState(EditorState.createEmpty());\n  const editor = useRef(null);\n\n  const focus = () => {\n    if (editor.current) editor.current.focus();\n  };\n\n  const handleKeyCommand = useCallback(\n    (command, editorState) => {\n      const newState = RichUtils.handleKeyCommand(editorState, command);\n      if (newState) {\n        setEditorState(newState);\n        return 'handled';\n      }\n      return 'not-handled';\n    },\n    [editorState, setEditorState],\n  );\n\n  const mapKeyToEditorCommand = useCallback(\n    e => {\n      switch (e.keyCode) {\n        case 9: // TAB\n          const newEditorState = RichUtils.onTab(\n            e,\n            editorState,\n            4 /* maxDepth */,\n          );\n          if (newEditorState !== editorState) {\n            setEditorState(newEditorState);\n          }\n          return null;\n      }\n      return getDefaultKeyBinding(e);\n    },\n    [editorState, setEditorState],\n  );\n\n  // If the user changes block type before entering any text, we can\n  // either style the placeholder or hide it. Let's just hide it now.\n  let className = 'RichEditor-editor';\n  var contentState = editorState.getCurrentContent();\n  if (!contentState.hasText()) {\n    if (\n      contentState\n        .getBlockMap()\n        .first()\n        .getType() !== 'unstyled'\n    ) {\n      className += ' RichEditor-hidePlaceholder';\n    }\n  }\n\n  return (\n    <div className=\"RichEditor-root\">\n      <BlockStyleControls\n        editorState={editorState}\n        onToggle={blockType => {\n          const newState = RichUtils.toggleBlockType(editorState, blockType);\n          setEditorState(newState);\n        }}\n      />\n      <InlineStyleControls\n        editorState={editorState}\n        onToggle={inlineStyle => {\n          const newState = RichUtils.toggleInlineStyle(\n            editorState,\n            inlineStyle,\n          );\n          setEditorState(newState);\n        }}\n      />\n      <div className={className} onClick={focus}>\n        <Editor\n          blockStyleFn={getBlockStyle}\n          customStyleMap={styleMap}\n          editorState={editorState}\n          handleKeyCommand={handleKeyCommand}\n          keyBindingFn={mapKeyToEditorCommand}\n          onChange={setEditorState}\n          placeholder=\"Tell a story...\"\n          ref={editor}\n          spellCheck={true}\n        />\n      </div>\n    </div>\n  );\n}\n\n// Custom overrides for \"code\" style.\nconst styleMap = {\n  CODE: {\n    backgroundColor: 'rgba(0, 0, 0, 0.05)',\n    fontFamily: '\"Inconsolata\", \"Menlo\", \"Consolas\", monospace',\n    fontSize: 16,\n    padding: 2,\n  },\n};\n\nfunction getBlockStyle(block) {\n  switch (block.getType()) {\n    case 'blockquote':\n      return 'RichEditor-blockquote';\n    default:\n      return null;\n  }\n}\n\nfunction StyleButton({onToggle, active, label, style}) {\n  let className = 'RichEditor-styleButton';\n  if (active) {\n    className += ' RichEditor-activeButton';\n  }\n\n  return (\n    <span\n      className={className}\n      onMouseDown={e => {\n        e.preventDefault();\n        onToggle(style);\n      }}>\n      {label}\n    </span>\n  );\n}\n\nconst BLOCK_TYPES = [\n  {label: 'H1', style: 'header-one'},\n  {label: 'H2', style: 'header-two'},\n  {label: 'H3', style: 'header-three'},\n  {label: 'H4', style: 'header-four'},\n  {label: 'H5', style: 'header-five'},\n  {label: 'H6', style: 'header-six'},\n  {label: 'Blockquote', style: 'blockquote'},\n  {label: 'UL', style: 'unordered-list-item'},\n  {label: 'OL', style: 'ordered-list-item'},\n  {label: 'Code Block', style: 'code-block'},\n];\n\nfunction BlockStyleControls({editorState, onToggle}) {\n  const selection = editorState.getSelection();\n  const blockType = editorState\n    .getCurrentContent()\n    .getBlockForKey(selection.getStartKey())\n    .getType();\n\n  return (\n    <div className=\"RichEditor-controls\">\n      {BLOCK_TYPES.map(type => (\n        <StyleButton\n          key={type.label}\n          active={type.style === blockType}\n          label={type.label}\n          onToggle={onToggle}\n          style={type.style}\n        />\n      ))}\n    </div>\n  );\n}\n\nconst INLINE_STYLES = [\n  {label: 'Bold', style: 'BOLD'},\n  {label: 'Italic', style: 'ITALIC'},\n  {label: 'Underline', style: 'UNDERLINE'},\n  {label: 'Monospace', style: 'CODE'},\n];\n\nfunction InlineStyleControls({editorState, onToggle}) {\n  const currentStyle = editorState.getCurrentInlineStyle();\n  return (\n    <div className=\"RichEditor-controls\">\n      {INLINE_STYLES.map(type => (\n        <StyleButton\n          key={type.label}\n          active={currentStyle.has(type.style)}\n          label={type.label}\n          onToggle={onToggle}\n          style={type.style}\n        />\n      ))}\n    </div>\n  );\n}\n\nexport default RichEditorExample;\n"
  },
  {
    "path": "website/src/css/custom.css",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n:root {\n  --ifm-color-primary: #843131;\n  --ifm-color-primary-dark: rgb(119, 44, 44);\n  --ifm-color-primary-darker: rgb(112, 42, 42);\n  --ifm-color-primary-darkest: rgb(92, 34, 34);\n  --ifm-color-primary-light: rgb(150, 80, 80);\n  --ifm-color-primary-lighter: rgb(169, 111, 111);\n  --ifm-color-primary-lightest: rgb(194, 152, 152);\n  --ifm-code-font-size: 95%;\n}\n\n.main-wrapper a:link:not(.button) {\n  text-decoration: underline;\n}\n"
  },
  {
    "path": "website/src/pages/index.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport React from 'react';\nimport Link from '@docusaurus/Link';\nimport useDocusaurusContext from '@docusaurus/useDocusaurusContext';\nimport useBaseUrl from '@docusaurus/useBaseUrl';\n\nimport Layout from '@theme/Layout';\n\nimport classnames from 'classnames';\n\nimport DraftEditorExample from '../components/DraftEditorExample';\nimport styles from './styles.module.css';\n\n/** Won't render children on server */\nfunction ClientOnly({children, fallback}) {\n  if (typeof window === 'undefined') {\n    return fallback || null;\n  }\n  return children;\n}\n\nfunction VideoContainer() {\n  return (\n    <div className=\"container text--center margin-bottom--xl margin-top--lg\">\n      <div className=\"row\">\n        <div className=\"col\">\n          <h2>Check it out in the intro video</h2>\n            <iframe\n              width=\"560\"\n              height=\"315\"\n              src=\"https://www.youtube.com/embed/YEK7SXFrJL4\"\n              title=\"Explain Like I'm 5: DraftJS\"\n              frameBorder=\"0\"\n              allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\"\n              allowFullScreen\n            />\n        </div>\n      </div>\n    </div>\n  );\n}\n\nfunction Home() {\n  const context = useDocusaurusContext();\n  const {siteConfig = {}} = context;\n\n  return (\n    <Layout permalink=\"/\" description={siteConfig.tagline}>\n      <div className=\"hero hero--primary shadow--lw\">\n        <div className=\"container\">\n          <div className=\"row\">\n            <div className=\"col\">\n              <h1 className=\"hero__title\">{siteConfig.title}</h1>\n              <p className=\"hero__subtitle\">{siteConfig.tagline}</p>\n              <div>\n                <Link\n                  className=\"button button--secondary button--lg\"\n                  to={useBaseUrl('docs/getting-started')}>\n                  Get Started\n                </Link>\n              </div>\n            </div>\n            <div className=\"col text--center\">\n              <img\n                className={styles.demoGif}\n                src={useBaseUrl('/img/demo.gif')}\n              />\n            </div>\n          </div>\n        </div>\n      </div>\n      <VideoContainer />\n      <div className=\"container\">\n        <div className=\"margin-vert--xl\">\n          <div className=\"row\">\n            <div className=\"col\">\n              <h3>Extensible and Customizable</h3>\n              <p>\n                We provide the building blocks to enable the creation of a broad\n                variety of rich text composition experiences, from basic text\n                styles to embedded media.\n              </p>\n            </div>\n            <div className=\"col\">\n              <h3>Declarative Rich Text</h3>\n              <p>\n                Draft.js fits seamlessly into React applications, abstracting\n                away the details of rendering, selection, and input behavior\n                with a familiar declarative API.\n              </p>\n            </div>\n            <div className=\"col\">\n              <h3>Immutable Editor State</h3>\n              <p>\n                The Draft.js model is built with{' '}\n                <a\n                  href=\"https://immutable-js.github.io/immutable-js/\"\n                  target=\"_blank\"\n                  rel=\"noreferrer noopener\">\n                  immutable-js\n                </a>\n                , offering an API with functional state updates and aggressively\n                leveraging data persistence for scalable memory usage.\n              </p>\n            </div>\n          </div>\n        </div>\n        <div\n          className={classnames(\n            'row',\n            'margin-vert--xl',\n            styles.hideOnTabletAndSmaller,\n          )}>\n          <ClientOnly fallback={null}>\n            <div className=\"col col--6 col--offset-3\">\n              <h2>Try it out!</h2>\n              <p>\n                Here's a simple example of a rich text editor built in Draft.js.\n              </p>\n              <div id=\"rich-example\">\n                <DraftEditorExample />\n              </div>\n            </div>\n          </ClientOnly>\n        </div>\n        <div className=\"margin-vert--xl text--center\">\n          <Link\n            className=\"button button--primary button--lg\"\n            to={useBaseUrl('docs/getting-started')}>\n            Learn more about Draft.js\n          </Link>\n        </div>\n      </div>\n    </Layout>\n  );\n}\n\nexport default Home;\n"
  },
  {
    "path": "website/src/pages/styles.module.css",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n@media only screen and (max-width: 996px) {\n  .demoGif {\n    margin-top: 2rem;\n    width: 100%;\n  }\n\n  .hideOnTabletAndSmaller {\n    display: none;\n  }\n}\n\n\n/* Announcement banner */\n\n:root {\n  --docusaurus-announcement-bar-height: auto !important;\n}\n\ndiv[class^=\"announcementBarContent\"] {\n  line-height: 40px;\n  font-size: 20px;\n  font-weight: bold;\n  padding: 8px 30px;\n}\n\ndiv[class^=\"announcementBarContent\"] a {\n  text-decoration: underline;\n  display: inline-block;\n  color: var(--ifm-color-primary-lightest) !important;\n}\n\ndiv[class^=\"announcementBarContent\"] a:hover {\n  color: var(--brand) !important;\n}\n\n@media only screen and (max-width: 768px) {\n  .announcement {\n    font-size: 18px;\n  }\n}\n\n@media only screen and (max-width: 500px) {\n  .announcement {\n    font-size: 15px;\n    line-height: 22px;\n    padding: 6px 30px;\n  }\n}\n"
  },
  {
    "path": "website/static/CNAME",
    "content": "draftjs.org\n"
  }
]