[
  {
    "path": ".bookignore",
    "content": ".github/\n__tests__/\nexamples/\nlib/\nscratch/\nsrc/\n"
  },
  {
    "path": ".editorconfig",
    "content": "# http://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\nend_of_line = lf\ninsert_final_newline = true\n"
  },
  {
    "path": ".github/CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\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 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 address, without explicit permission\n- Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at jon.gold@airbnb.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "# Contributing\n\nContributions are welcome and are greatly appreciated! Every little bit helps, and credit will always be given. By contributing, you agree to abide by the [code of conduct](https://github.com/airbnb/react-sketchapp/blob/master/.github/CODE_OF_CONDUCT.md).\n\n## Reporting Issues and Asking Questions\n\n**For support or usage questions like “how do I do X with react-sketchapp” and “my code doesn't work”, please search and ask on [StackOverflow with a react-sketchapp tag](http://stackoverflow.com/questions/tagged/react-sketchapp?sort=votes&pageSize=50) first.**\n\nWe ask you to do this because StackOverflow does a much better job at keeping popular questions visible. Unfortunately good answers get lost and outdated on GitHub.\n\nSome questions take a long time to get an answer. **If your question gets closed or you don't get a reply on StackOverflow for longer than a few days,** we encourage you to post an issue linking to your question. We will close your issue but this will give people watching the repo an opportunity to see your question and reply to it on StackOverflow if they know the answer.\n\nPlease be considerate when doing this as this is not the primary purpose of the issue tracker.\n\n### Help Us Help You\n\nOn both websites, it is a good idea to structure your code and question in a way that is easy to read to entice people to answer it. For example, we encourage you to use syntax highlighting, indentation, and split text in paragraphs.\n\nPlease keep in mind that people spend their free time trying to help you. You can make it easier for them if you provide versions of the relevant libraries and a runnable small project reproducing your issue. You can put your code on [JSBin](http://jsbin.com) or, for bigger projects, on GitHub. Make sure all the necessary dependencies are declared in `package.json` so anyone can run `npm install && npm start` and reproduce your issue.\n\n## Development\n\nVisit the [issue tracker](https://github.com/airbnb/react-sketchapp/issues) to find a list of open issues that need attention.\n\nFork, then clone the repo\n\n```bash\ngit clone https://github.com/your-username/react-sketchapp.git\n```\n\n### Setting up your environment\n\n### Testing, style & Linting\n\nTo run tests\n\n```bash\nnpm run test\n```\n\nTo run tests continuously\n\n```bash\nnpm run test:watch\n```\n\nThis style of the codebase is enforced by [Prettier](https://prettier.io/).\n\nIt is recommended that you install a Prettier plugin for your editor of choice when working on this codebase.\n\n### Docs\n\nWe always appreciate improvements to the documentation!\n\n#### Installing Gitbook\n\nTo install the latest version of `gitbook` and prepare to build the documentation, run the following:\n\n```\nnpm run docs:prepare\n```\n\n#### Building the Docs\n\nTo build the documentation, run the following:\n\n```\nnpm run docs:build\n```\n\nTo watch and rebuild documentation when changes occur, run the following:\n\n```\nnpm run docs:watch\n```\n\nThe docs will be served at http://localhost:4000.\n\n#### Publishing the Docs\n\nTo publish the documentation, run the following:\n\n```\nnpm run docs:publish\n```\n\n### Sending a Pull Request\n\nFor non-trivial changes, please open an issue with a proposal for a new feature or refactoring before starting work — we don't want you to waste your time on a pull request that won't be accepted.\n\nOn the other hand, sometimes the best way to start a discussion _is_ to send a pull request. Use your judgement!\n\nIn general, the contribution workflow looks like this:\n\n- Open a new issue in the [Issue tracker](https://github.com/airbnb/react-sketchapp/issues).\n- Fork the repo.\n- Create a new feature branch based off the `master` branch.\n- Make sure all tests pass.\n- Submit a pull request, referencing any issues it addresses.\n\nPlease try to keep your pull request focused in scope and avoid including unrelated commits.\n\nAfter you have submitted your pull request, we'll try to get back to you as soon as possible. We may suggest some changes or improvements.\n\nThank you for contributing!\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "👋 Hello! Thanks for contributing. Please use the template that matches your intention  \n\n_I am..._\n\n| -------------------------------------------------------------------------------------------------\n| Requesting a new feature\n| -------------------------------------------------------------------------------------------------\n\n**Proposal/Feature-request:**\n\n| -------------------------------------------------------------------------------------------------\n| Reporting a bug or issue\n| -------------------------------------------------------------------------------------------------\n\n**Expected behavior:**\n\n**Observed behavior:**\n\n**How to reproduce:**\n\n**Sketch version:**\n\n**Please attach screenshots, a zip file of your project, and/or a link to your github project**\n"
  },
  {
    "path": ".gitignore",
    "content": "# gitignore\ncoverage/\n.DS_Store\n*.log*\nnode_modules\nlib\nreact-example.sketchplugin\n_book\n.vscode\n\n# only apps should have lockfiles\nyarn.lock\npackage-lock.json\nnpm-shrinkwrap.json\n"
  },
  {
    "path": ".npmignore",
    "content": ".DS_Store\n*.log*\nnode_modules\n_book\nexamples\ndocs\n.vscode\nyarn.lock\n__tests__\n.github\ntemplate\nbook.json\nprettier.config.js\n.editorconfig\n.bookignore\nsrc\njest.config.js\ntsconfig.json\ntsconfig.module.json\n.travis.yml\n"
  },
  {
    "path": ".travis.yml",
    "content": "os: osx\nlanguage: node_js\ncache:\n  directories:\n    - node_modules\n#     - $HOME/Library/Caches/Homebrew\nnotifications:\n  email: false\nnode_js:\n  - 'lts/*'\n# before_install:\n#   - brew update\n#   - brew cask install sketch # install Sketch\n#   - mkdir -p \"~/Library/Application Support/com.bohemiancoding.sketch3/Plugins\" # create plugins folder\n#   - echo $SKETCH_LICENSE > \"~/Library/Application Support/com.bohemiancoding.sketch3/.deployment\" # add the Sketch license\nbefore_script:\n  - npm prune\nscript:\n  - npm run test:ci\n  # - npm run test:e2e -- --app=/Applications/Sketch.app\n# after_script:\n#   - rm \"~/Library/App Support/com.bohemiancoding.sketch3/.deployment\" # remove the Sketch license\nbranches:\n  except:\n    - /^v\\d+\\.\\d+\\.\\d+$/\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Change Log\n\nThis project adheres to [Semantic Versioning](http://semver.org/). Every release, along with the migration instructions, is documented on the Github [Releases](https://github.com/airbnb/react-sketchapp/releases) page.\n\n## Version 3.2.6\n\n- Fix the SVG component export\n\n## Version 3.2.5\n\n- Fix Skpm taking the wrong entry point when requiring react-sketchapp\n\n## Version 3.2.4\n\n- Fix the generated ES package\n\n## Version 3.2.3\n\n- Fix getting the font name (#510)\n\n## Version 3.2.2\n\n- Fix getting the default bridge on NodeJS\n\n## Version 3.2.1\n\n- `Platform.version` now reflects the Sketch version\n- Fix a bug for a broken version of `@sketch-hq/sketch-file-format-ts`\n\n## Version 3.2.0\n\n- Add a new `useWindowDimensions` hook for Artboard viewport (#501)\n\n## Version 3.1.3\n\n- Add proptypes for Text\n- Allow `fontWeigth` to be a number\n\n## Version 3.1.2\n\n- Handle passing a Sketch document more properly\n\n## Version 3.1.1\n\n- Fix for Sketch 64\n\n## Version 3.1.0\n\n- Fix acceptable text children (#474)\n- Fix parsing of SVG arc shorthand parameters (#467)\n- Change default font resolution, always falling back to the system font when the `fontFamily` is missing or not specified\n\n## Version 3.0.5\n\n- Fix missing dependency (#462)\n\n## Version 3.0.4\n\n- Fix rendering images (#458)\n\n## Version 3.0.3\n\n- Fix typo in Symbol (Thanks @antoni!)\n- Fix messed up `js-sha` import (#456)\n\n## Version 3.0.2\n\n- Fix rotation direction (#433)\n- Fix Svg renders when the shape doesn't fit the viewbox (#288)\n- Add missing strokeAlignment prop (#276)\n\n## Version 3.0.1\n\n- Allow passing a style object when making a symbol\n- Expose `getSymbolMasterByName`\n\n## Version 3.0.0\n\n- Export Svg components in the Svg/index.js file (Thanks @saschazar21!)\n- Fix setting the overflow\n- The symbol masters will try to maintain their overrides IDs so as not to reset instances that have overrides\n- Improve error messages when trying to render a broken override\n- Do not crash if there is no source for an Image, we will just show an placeholder for the image\n- Handle specifying document in injectSymbols (#388)\n- Add support for paragraph spacing (#382 - Thanks @lessthanzero!)\n- `Image` and `Text` now support multiple shadows just like `View`\n- Add support for `TextShadow`\n- Add support for `transform`\n- Add support for running `react-sketchapp` on NodeJS using `renderToJSON()`\n- Port to TypeScript and publish TypeScript definitions\n- `TextStyles.get(name)` now returns text styles that are part of the document (even if they haven't been defined with `react-sketchapp`) (#407)\n- `getSymbolComponentByName` now returns Symbols that are part of the document (even if they haven't been defined with `react-sketchapp`) (#177)\n- Switch the order of the `TextStyles.create` arguments to `TextStyles.create(styles, options)`\n\n## Version 3.0.0-beta.9\n\n- Fix setting the overflow\n- The symbol masters will try to maintain their overrides IDs so as not to reset instances that have overrides\n- Improve error messages when trying to render a broken override\n- Export Svg components in the Svg/index.js file (Thanks @saschazar21!)\n\n## Version 3.0.0-beta.8\n\n- Flatten styles in exported Svg component (Thanks @dabbott!)\n\n## Version 3.0.0-beta.7\n\n- Add Node.js SVG renderer (Thanks @dabbott!)\n\n## Version 3.0.0-beta.6\n\n- Do not crash if there is no source for an Image, we will just show an placeholder for the image\n\n## Version 3.0.0-beta.3 to 3.0.0-beta.5\n\n- Fix setting overrides (#409)\n- Fix images on NodeJS\n- Fix Border-radius clipping incorrectly calculated (#279)\n\n## Version 3.0.0-beta.1\n\n- Fix ShapeGroup on nodejs (#387)\n- Handle specifying document in injectSymbols (#388)\n- Fix support for paragraph spacing on sketch >= 49 (#390)\n\n## Version 3.0.0-beta.0\n\n- Add support for paragraph spacing (#382 - Thanks @lessthanzero!)\n- `Image` and `Text` now support multiple shadows just like `View`\n- add support for `TextShadow`\n- Experimental support for `transform`\n- Experimental support for running `react-sketchapp` on NodeJS\n\n## Version 2.1.0\n\n- Ensure `makeSymbol` does not change currentPage (#353 - Thanks @jaridmargolin!)\n- Fix Text decoration underline style (#370 - Thanks @thecalvinchan!)\n- Add possibility to add multiple shadows and shadow spread (#277 - Thanks @ludwigfrank and @thierryc!)\n- Support rendering into wrapped object (hence support the new Sketch API) (#379)\n\n## Version 2.0.0\n\n- Now throws if the \"Symbols\" page is explicitly passed in as the `container` on the `render` method. Previously if you explicitly passed in the \"Symbols\" pages as a container, it would create a new page and render onto that. (#297 - Thanks @jaridmargolin!)\n- Now throws an error if you attempt to render a Document component into a node intended to be a child of `Document`. (#297 - Thanks @jaridmargolin!)\n- Adds support for rendering a `Page` component into a container passed through the `render` method. This allows for rendering multiple `Artboard`s onto an existing page. (#297 - Thanks @jaridmargolin!)\n- More predictable rendering of `RedBox`. (#297 - Thanks @jaridmargolin!)\n- Fix Symbols overrides for Sketch >= 46 (#198 - Thanks @ianhook!)\n- Fix text overrides when the name of the Text layer is not explicitly defined (#292 - Thanks @jaridmargolin!)\n- update `yoga-node` to 1.9 (#314)\n- Add support for Sketch 50 (#290)\n- Fix shared text style matching (#290)\n- Remove n^2 rendering problem with large symbol sets (#235 - Thanks @ianhook!)\n- `Page` without a name explicitly set will be auto-incremented (\"Page 1\", \"Page 2\", etc.) just like how Sketch is doing by default (#296 - Thanks @jaridmargolin!)\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Airbnb\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": "README.md",
    "content": "<div align=\"center\">\n  <img alt=\"react-sketchapp\" src=\"https://cldup.com/MxSVEkc_gb.png\" style=\"max-height:163px; width:100; height: auto; max-width:100%\" />\n</div>\n\n<div align=\"center\">\n  <strong>render React components to Sketch; tailor-made for design systems</strong>\n</div>\n\n## Quick-start 🏃‍\n\nFirst, make sure you have installed [Sketch](http://sketch.com) version 50+, & a recent [npm](https://nodejs.org/en/download/).\n\nOpen a new Sketch file, then in a terminal:\n\n```bash\ngit clone https://github.com/airbnb/react-sketchapp.git\ncd react-sketchapp/examples/basic-setup && npm install\n\nnpm run render\n```\n\nNext, [check out some more examples](https://github.com/airbnb/react-sketchapp/tree/master/examples)!\n\n![readme-intro](https://cloud.githubusercontent.com/assets/591643/24777148/e742cd0e-1ad8-11e7-8751-090f6b2db514.png)\n\n[![npm](https://img.shields.io/npm/v/react-sketchapp.svg)](https://www.npmjs.com/package/react-sketchapp) ![Sketch.app](https://img.shields.io/badge/Sketch.app-43--50-brightgreen.svg) [![Travis](https://img.shields.io/travis/rust-lang/rust.svg)](https://travis-ci.org/airbnb/react-sketchapp)\n\n## Why?!\n\nManaging the assets of design systems in Sketch is complex, error-prone and time consuming. Sketch is scriptable, but the API often changes. React provides the perfect wrapper to build reusable documents in a way already familiar to JavaScript developers.\n\n## What does the code look like?\n\n```js\nimport * as React from 'react';\nimport { render, Text, Artboard } from 'react-sketchapp';\n\nconst App = props => (\n  <Artboard>\n    <Text style={{ fontFamily: 'Comic Sans MS', color: 'hotPink' }}>{props.message}</Text>\n  </Artboard>\n);\n\nexport default context => {\n  render(<App message=\"Hello world!\" />, context.document.currentPage());\n};\n```\n\n## What can I do with it?\n\n- **Manage design systems—** `react-sketchapp` was built for [Airbnb’s design system](http://airbnb.design/building-a-visual-language/); this is the easiest way to manage Sketch assets in a large design system\n- **Use real components for designs—** Implement your designs in code as React components and render them into Sketch\n- **Design with real data—** Designing with data is important but challenging; `react-sketchapp` makes it simple to fetch and incorporate real data into your Sketch files\n- **Build new tools on top of Sketch—** the easiest way to use Sketch as a canvas for custom design tooling\n\nFound a novel use? We'd love to hear about it!\n\n[Read more about why we built it](http://airbnb.design/painting-with-code/)\n\n## Documentation\n\n- [Examples](http://airbnb.io/react-sketchapp/docs/examples.html)\n- [API Reference](http://airbnb.io/react-sketchapp/docs/API.html)\n- [Styling](http://airbnb.io/react-sketchapp/docs/guides/styling.html)\n- [Universal Rendering](http://airbnb.io/react-sketchapp/docs/guides/universal-rendering.html)\n- [Data Fetching](http://airbnb.io/react-sketchapp/docs/guides/data-fetching.html)\n- [FAQ](http://airbnb.io/react-sketchapp/docs/FAQ.html)\n- [Contributing](https://github.com/airbnb/react-sketchapp/blob/master/.github/CONTRIBUTING.md)\n"
  },
  {
    "path": "__tests__/jest/components/Artboard.tsx",
    "content": "import * as React from 'react';\nimport * as renderer from 'react-test-renderer';\nimport { Artboard } from '../../../src/components/Artboard';\nimport { StyleSheet } from '../../../src/stylesheet';\n\ndescribe('<Artboard />', () => {\n  it('renders children', () => {\n    const tree = renderer.create(<Artboard>foo</Artboard>).toJSON();\n\n    expect(tree).toMatchSnapshot();\n  });\n\n  it.todo('flattens its stylesheet');\n\n  describe('name', () => {\n    it('passes its name', () => {\n      const tree = renderer.create(<Artboard name=\"bar\" />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('defaults to Artboard', () => {\n      const tree = renderer.create(<Artboard />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n  });\n\n  describe('style', () => {\n    const styles = StyleSheet.create({\n      view: {\n        flex: 1,\n      },\n    });\n\n    it('accepts a plain object', () => {\n      const tree = renderer.create(<Artboard style={{ flex: 1 }} />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('accepts a StyleSheet ordinal', () => {\n      const tree = renderer.create(<Artboard style={styles.view} />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('accepts an array of plain objects and/or StyleSheet ordinals', () => {\n      const tree = renderer.create(<Artboard style={[{ flexGrow: 1 }, styles.view]} />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('accepts artboard viewport preset', () => {\n      const tree = renderer\n        .create(\n          <Artboard\n            style={{ flex: 1, width: 360, height: 1280 }}\n            viewport={{\n              name: 'Mobile',\n              width: 360,\n              height: 640,\n            }}\n          />,\n        )\n        .toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n  });\n});\n"
  },
  {
    "path": "__tests__/jest/components/Document.tsx",
    "content": "import * as React from 'react';\nimport * as renderer from 'react-test-renderer';\nimport { Document } from '../../../src/components/Document';\n\ndescribe('<Document />', () => {\n  it('renders children', () => {\n    const tree = renderer.create(<Document>foo</Document>).toJSON();\n\n    expect(tree).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "__tests__/jest/components/Image.tsx",
    "content": "import * as React from 'react';\nimport * as renderer from 'react-test-renderer';\nimport { Image } from '../../../src/components/Image';\nimport { StyleSheet } from '../../../src/stylesheet';\n\ndescribe('<Image />', () => {\n  it('renders children', () => {\n    const tree = renderer.create(<Image source=\"foo\">foo</Image>).toJSON();\n\n    expect(tree).toMatchSnapshot();\n  });\n\n  it.todo('flattens its stylesheet');\n\n  describe('name', () => {\n    it('passes its name', () => {\n      const tree = renderer.create(<Image source=\"foo\" name=\"bar\" />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('defaults to Image', () => {\n      const tree = renderer.create(<Image source=\"foo\" />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n  });\n\n  describe('resizeMode', () => {\n    it('translates contain', () => {\n      const tree = renderer.create(<Image source=\"foo\" resizeMode=\"contain\" />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('translates cover', () => {\n      const tree = renderer.create(<Image source=\"foo\" resizeMode=\"cover\" />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('translates stretch', () => {\n      const tree = renderer.create(<Image source=\"foo\" resizeMode=\"stretch\" />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('translates center', () => {\n      const tree = renderer.create(<Image source=\"foo\" resizeMode=\"center\" />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('translates repeat', () => {\n      const tree = renderer.create(<Image source=\"foo\" resizeMode=\"repeat\" />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('translates none', () => {\n      const tree = renderer.create(<Image source=\"foo\" resizeMode=\"none\" />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('falls back to cover', () => {\n      const tree = renderer.create(<Image source=\"foo\" />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('prefers prop to style', () => {\n      const tree = renderer\n        .create(<Image source=\"foo\" resizeMode=\"cover\" style={{ resizeMode: 'contain' }} />)\n        .toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('falls back to a resizeMode from style', () => {\n      const tree = renderer\n        .create(<Image source=\"foo\" style={{ resizeMode: 'contain' }} />)\n        .toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n  });\n\n  describe('source', () => {\n    it('prefers source over defaultSource', () => {\n      const tree = renderer.create(<Image source=\"foo\" defaultSource=\"bar\" />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('falls back to defaultSource if available', () => {\n      const tree = renderer.create(<Image defaultSource=\"foo\" />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('sets height from source', () => {\n      const tree = renderer.create(<Image source={{ uri: 'foo', height: 500 }} />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('sets width from source', () => {\n      const tree = renderer.create(<Image source={{ uri: 'foo', width: 500 }} />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('favors style over source for height', () => {\n      const tree = renderer\n        .create(<Image source={{ uri: 'foo', height: 500 }} style={{ height: 400, width: 300 }} />)\n        .toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('favors style over source for width', () => {\n      const tree = renderer\n        .create(<Image source={{ uri: 'foo', width: 500 }} style={{ height: 400, width: 300 }} />)\n        .toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n  });\n\n  describe('style', () => {\n    const styles = StyleSheet.create({\n      view: {\n        flex: 1,\n      },\n    });\n\n    it('accepts a plain object', () => {\n      const tree = renderer.create(<Image style={{ flex: 1 }} />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('accepts a StyleSheet ordinal', () => {\n      const tree = renderer.create(<Image style={styles.view} />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('accepts an array of plain objects and/or StyleSheet ordinals', () => {\n      const tree = renderer.create(<Image style={[{ flexGrow: 1 }, styles.view]} />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n  });\n});\n"
  },
  {
    "path": "__tests__/jest/components/Page.tsx",
    "content": "import * as React from 'react';\nimport * as renderer from 'react-test-renderer';\nimport { Page } from '../../../src/components/Page';\n\ndescribe('<Page />', () => {\n  it('renders children', () => {\n    const tree = renderer.create(<Page>foo</Page>).toJSON();\n\n    expect(tree).toMatchSnapshot();\n  });\n\n  describe('name', () => {\n    it('passes its name', () => {\n      const tree = renderer.create(<Page name=\"bar\" />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('passes its name and avoids Symbol page conflict', () => {\n      const tree = renderer.create(<Page name=\"Symbols\" />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('passes otherProps', () => {\n      // @ts-ignore\n      const tree = renderer.create(<Page propName=\"something\" style={{}} />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n  });\n});\n"
  },
  {
    "path": "__tests__/jest/components/RedBox.tsx",
    "content": "import * as React from 'react';\nimport * as renderer from 'react-test-renderer';\nimport { RedBox } from '../../../src/components/RedBox';\n\ndescribe('<RedBox />', () => {\n  it('renders simple errors', () => {\n    const mockedError = new Error('THIS IS AN ERROR');\n    // override stack trace so that it's constant accross node versions\n    mockedError.stack = `Error: awdawd\n  at repl:1:13\n  at Script.runInThisContext (vm.js:65:33)\n  at REPLServer.defaultEval (repl.js:248:29)\n  at bound (domain.js:375:14)\n  at REPLServer.runBound [as eval] (domain.js:388:12)\n  at REPLServer.onLine (repl.js:501:10)\n  at REPLServer.emit (events.js:185:15)\n  at REPLServer.emit (domain.js:421:20)\n  at REPLServer.Interface._onLine (readline.js:285:10)\n  at REPLServer.Interface._line (readline.js:638:8)`;\n    const tree = renderer.create(<RedBox error={mockedError} />).toJSON();\n\n    expect(tree).toMatchSnapshot();\n  });\n\n  it('renders string errors', () => {\n    const tree = renderer.create(<RedBox error=\"String only error\" />).toJSON();\n\n    expect(tree).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "__tests__/jest/components/Svg.tsx",
    "content": "import * as React from 'react';\nimport * as renderer from 'react-test-renderer';\nimport Svg, { G, Path } from '../../../src/components/Svg';\n\ndescribe('<Svg />', () => {\n  it('passes its children', () => {\n    const tree = renderer\n      .create(\n        <Svg xmlns=\"http://www.w3.org/2000/svg\" width=\"494\" height=\"447\" viewBox=\"0 0 494 447\">\n          <Svg.G fill=\"none\" fillRule=\"evenodd\">\n            <Svg.Path fill=\"#FFAE00\" d=\"M247 447L0 160 107 15 247 0l140 15 107 145\" />\n            <Svg.Path fill=\"#EC6C00\" d=\"M247 447L0 160h494\" />\n            <Svg.Path fill=\"#FFAE00\" d=\"M247 447L100 160h294\" />\n            <Svg.Path fill=\"#FFEFB4\" d=\"M247 0L100 160h294\" />\n            <Svg.Path fill=\"#FFAE00\" d=\"M107 15L52 88 0 160h101M387 15l55 73 52 72H393\" />\n            <Svg.Path fill=\"#FED305\" d=\"M107 15l-7 145L247 0m140 15l7 145L247 0\" />\n          </Svg.G>\n        </Svg>,\n      )\n      .toJSON();\n\n    expect(tree).toMatchSnapshot();\n  });\n\n  it('also works when child is directly imported', () => {\n    const tree = renderer.create(\n      <Svg xmlns=\"http://www.w3.org/2000/svg\" width=\"494\" height=\"447\" viewBox=\"0 0 494 447\">\n        <G fill=\"none\" fillRule=\"evenodd\">\n          <Path fill=\"#FFAE00\" d=\"M247 447L0 160 107 15 247 0l140 15 107 145\" />\n          <Path fill=\"#EC6C00\" d=\"M247 447L0 160h494\" />\n          <Path fill=\"#FFAE00\" d=\"M247 447L100 160h294\" />\n          <Path fill=\"#FFEFB4\" d=\"M247 0L100 160h294\" />\n          <Path fill=\"#FFAE00\" d=\"M107 15L52 88 0 160h101M387 15l55 73 52 72H393\" />\n          <Path fill=\"#FED305\" d=\"M107 15l-7 145L247 0m140 15l7 145L247 0\" />\n        </G>\n      </Svg>,\n    );\n\n    expect(tree.toJSON()).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "__tests__/jest/components/Text.tsx",
    "content": "import * as React from 'react';\nimport * as renderer from 'react-test-renderer';\nimport { Text } from '../../../src/components/Text';\nimport { StyleSheet } from '../../../src/stylesheet';\n\ndescribe('<Text />', () => {\n  it('passes its children', () => {\n    const tree = renderer.create(<Text>foo</Text>).toJSON();\n\n    expect(tree).toMatchSnapshot();\n  });\n\n  describe('name', () => {\n    it('passes its name', () => {\n      const tree = renderer.create(<Text name=\"foo\" />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('defaults to Text', () => {\n      const tree = renderer.create(<Text />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n  });\n\n  describe('style', () => {\n    const styles = StyleSheet.create({\n      view: {\n        flex: 1,\n      },\n    });\n\n    it('accepts a plain object', () => {\n      const tree = renderer.create(<Text style={{ flex: 1 }} />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('accepts a StyleSheet ordinal', () => {\n      const tree = renderer.create(<Text style={styles.view} />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('accepts an array of plain objects and/or StyleSheet ordinals', () => {\n      const tree = renderer.create(<Text style={[{ flexGrow: 1 }, styles.view]} />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n  });\n});\n"
  },
  {
    "path": "__tests__/jest/components/View.tsx",
    "content": "import * as React from 'react';\nimport * as renderer from 'react-test-renderer';\nimport { View } from '../../../src/components/View';\nimport { StyleSheet } from '../../../src/stylesheet';\n\ndescribe('<View />', () => {\n  it('passes its children', () => {\n    const tree = renderer.create(<View>foo</View>).toJSON();\n\n    expect(tree).toMatchSnapshot();\n  });\n\n  describe('name', () => {\n    it('passes its name', () => {\n      const tree = renderer.create(<View name=\"foo\" />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('defaults to View', () => {\n      const tree = renderer.create(<View />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n  });\n\n  describe('style', () => {\n    const styles = StyleSheet.create({\n      view: {\n        flex: 1,\n      },\n    });\n\n    it('accepts a plain object', () => {\n      const tree = renderer.create(<View style={{ flex: 1 }} />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('accepts a StyleSheet ordinal', () => {\n      const tree = renderer.create(<View style={styles.view} />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n\n    it('accepts an array of plain objects and/or StyleSheet ordinals', () => {\n      const tree = renderer.create(<View style={[{ flexGrow: 1 }, styles.view]} />).toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n  });\n});\n"
  },
  {
    "path": "__tests__/jest/components/__snapshots__/Artboard.tsx.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`<Artboard /> name defaults to Artboard 1`] = `\n<sketch_artboard\n  name=\"Artboard\"\n/>\n`;\n\nexports[`<Artboard /> name passes its name 1`] = `\n<sketch_artboard\n  name=\"bar\"\n/>\n`;\n\nexports[`<Artboard /> renders children 1`] = `\n<sketch_artboard\n  name=\"Artboard\"\n>\n  foo\n</sketch_artboard>\n`;\n\nexports[`<Artboard /> style accepts a StyleSheet ordinal 1`] = `\n<sketch_artboard\n  name=\"Artboard\"\n  style={\n    Object {\n      \"flex\": 1,\n    }\n  }\n/>\n`;\n\nexports[`<Artboard /> style accepts a plain object 1`] = `\n<sketch_artboard\n  name=\"Artboard\"\n  style={\n    Object {\n      \"flex\": 1,\n    }\n  }\n/>\n`;\n\nexports[`<Artboard /> style accepts an array of plain objects and/or StyleSheet ordinals 1`] = `\n<sketch_artboard\n  name=\"Artboard\"\n  style={\n    Object {\n      \"flex\": 1,\n      \"flexGrow\": 1,\n    }\n  }\n/>\n`;\n\nexports[`<Artboard /> style accepts artboard viewport preset 1`] = `\n<sketch_artboard\n  name=\"Artboard\"\n  style={\n    Object {\n      \"flex\": 1,\n      \"height\": 1280,\n      \"width\": 360,\n    }\n  }\n  viewport={\n    Object {\n      \"height\": 640,\n      \"name\": \"Mobile\",\n      \"width\": 360,\n    }\n  }\n/>\n`;\n"
  },
  {
    "path": "__tests__/jest/components/__snapshots__/Document.tsx.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`<Document /> renders children 1`] = `\n<sketch_document>\n  foo\n</sketch_document>\n`;\n"
  },
  {
    "path": "__tests__/jest/components/__snapshots__/Image.tsx.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`<Image /> name defaults to Image 1`] = `\n<sketch_image\n  name=\"Image\"\n  resizeMode={1}\n  source=\"foo\"\n  style={Object {}}\n/>\n`;\n\nexports[`<Image /> name passes its name 1`] = `\n<sketch_image\n  name=\"bar\"\n  resizeMode={1}\n  source=\"foo\"\n  style={Object {}}\n/>\n`;\n\nexports[`<Image /> renders children 1`] = `\n<sketch_image\n  name=\"Image\"\n  resizeMode={1}\n  source=\"foo\"\n  style={Object {}}\n>\n  foo\n</sketch_image>\n`;\n\nexports[`<Image /> resizeMode falls back to a resizeMode from style 1`] = `\n<sketch_image\n  name=\"Image\"\n  resizeMode={3}\n  source=\"foo\"\n  style={\n    Object {\n      \"resizeMode\": \"contain\",\n    }\n  }\n/>\n`;\n\nexports[`<Image /> resizeMode falls back to cover 1`] = `\n<sketch_image\n  name=\"Image\"\n  resizeMode={1}\n  source=\"foo\"\n  style={Object {}}\n/>\n`;\n\nexports[`<Image /> resizeMode prefers prop to style 1`] = `\n<sketch_image\n  name=\"Image\"\n  resizeMode={1}\n  source=\"foo\"\n  style={\n    Object {\n      \"resizeMode\": \"contain\",\n    }\n  }\n/>\n`;\n\nexports[`<Image /> resizeMode translates center 1`] = `\n<sketch_image\n  name=\"Image\"\n  resizeMode={1}\n  source=\"foo\"\n  style={Object {}}\n/>\n`;\n\nexports[`<Image /> resizeMode translates contain 1`] = `\n<sketch_image\n  name=\"Image\"\n  resizeMode={3}\n  source=\"foo\"\n  style={Object {}}\n/>\n`;\n\nexports[`<Image /> resizeMode translates cover 1`] = `\n<sketch_image\n  name=\"Image\"\n  resizeMode={1}\n  source=\"foo\"\n  style={Object {}}\n/>\n`;\n\nexports[`<Image /> resizeMode translates none 1`] = `\n<sketch_image\n  name=\"Image\"\n  resizeMode={1}\n  source=\"foo\"\n  style={Object {}}\n/>\n`;\n\nexports[`<Image /> resizeMode translates repeat 1`] = `\n<sketch_image\n  name=\"Image\"\n  resizeMode={0}\n  source=\"foo\"\n  style={Object {}}\n/>\n`;\n\nexports[`<Image /> resizeMode translates stretch 1`] = `\n<sketch_image\n  name=\"Image\"\n  resizeMode={2}\n  source=\"foo\"\n  style={Object {}}\n/>\n`;\n\nexports[`<Image /> source falls back to defaultSource if available 1`] = `\n<sketch_image\n  name=\"Image\"\n  resizeMode={1}\n  source=\"foo\"\n  style={Object {}}\n/>\n`;\n\nexports[`<Image /> source favors style over source for height 1`] = `\n<sketch_image\n  name=\"Image\"\n  resizeMode={1}\n  source={\n    Object {\n      \"height\": 500,\n      \"uri\": \"foo\",\n    }\n  }\n  style={\n    Object {\n      \"height\": 400,\n      \"width\": 300,\n    }\n  }\n/>\n`;\n\nexports[`<Image /> source favors style over source for width 1`] = `\n<sketch_image\n  name=\"Image\"\n  resizeMode={1}\n  source={\n    Object {\n      \"uri\": \"foo\",\n      \"width\": 500,\n    }\n  }\n  style={\n    Object {\n      \"height\": 400,\n      \"width\": 300,\n    }\n  }\n/>\n`;\n\nexports[`<Image /> source prefers source over defaultSource 1`] = `\n<sketch_image\n  name=\"Image\"\n  resizeMode={1}\n  source=\"foo\"\n  style={Object {}}\n/>\n`;\n\nexports[`<Image /> source sets height from source 1`] = `\n<sketch_image\n  name=\"Image\"\n  resizeMode={1}\n  source={\n    Object {\n      \"height\": 500,\n      \"uri\": \"foo\",\n    }\n  }\n  style={\n    Object {\n      \"height\": 500,\n      \"width\": undefined,\n    }\n  }\n/>\n`;\n\nexports[`<Image /> source sets width from source 1`] = `\n<sketch_image\n  name=\"Image\"\n  resizeMode={1}\n  source={\n    Object {\n      \"uri\": \"foo\",\n      \"width\": 500,\n    }\n  }\n  style={\n    Object {\n      \"height\": undefined,\n      \"width\": 500,\n    }\n  }\n/>\n`;\n\nexports[`<Image /> style accepts a StyleSheet ordinal 1`] = `\n<sketch_image\n  name=\"Image\"\n  resizeMode={1}\n  style={\n    Object {\n      \"flex\": 1,\n    }\n  }\n/>\n`;\n\nexports[`<Image /> style accepts a plain object 1`] = `\n<sketch_image\n  name=\"Image\"\n  resizeMode={1}\n  style={\n    Object {\n      \"flex\": 1,\n    }\n  }\n/>\n`;\n\nexports[`<Image /> style accepts an array of plain objects and/or StyleSheet ordinals 1`] = `\n<sketch_image\n  name=\"Image\"\n  resizeMode={1}\n  style={\n    Object {\n      \"flex\": 1,\n      \"flexGrow\": 1,\n    }\n  }\n/>\n`;\n"
  },
  {
    "path": "__tests__/jest/components/__snapshots__/Page.tsx.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`<Page /> name passes its name 1`] = `\n<sketch_page\n  name=\"bar\"\n/>\n`;\n\nexports[`<Page /> name passes its name and avoids Symbol page conflict 1`] = `\n<sketch_page\n  name=\"Symbols (renamed to avoid conflict)\"\n/>\n`;\n\nexports[`<Page /> name passes otherProps 1`] = `\n<sketch_page\n  propName=\"something\"\n  style={Object {}}\n/>\n`;\n\nexports[`<Page /> renders children 1`] = `\n<sketch_page>\n  foo\n</sketch_page>\n`;\n"
  },
  {
    "path": "__tests__/jest/components/__snapshots__/RedBox.tsx.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`<RedBox /> renders simple errors 1`] = `\n<sketch_view\n  name=\"RedBox\"\n  style={\n    Object {\n      \"backgroundColor\": \"rgb(204, 0, 0)\",\n      \"paddingBottom\": 10,\n      \"paddingLeft\": 10,\n      \"paddingRight\": 10,\n      \"paddingTop\": 10,\n      \"width\": 480,\n    }\n  }\n>\n  <sketch_text\n    name=\"Message\"\n    style={\n      Object {\n        \"color\": \"white\",\n        \"fontSize\": 16,\n        \"fontWeight\": \"bold\",\n        \"lineHeight\": 19.2,\n      }\n    }\n  >\n    Error: THIS IS AN ERROR\n  </sketch_text>\n  <sketch_view\n    name=\"Frames\"\n    style={\n      Object {\n        \"color\": \"white\",\n        \"fontFamily\": \"Monaco\",\n        \"marginTop\": 20,\n      }\n    }\n  >\n    <sketch_text\n      style={\n        Object {\n          \"color\": \"white\",\n          \"fontFamily\": \"Monaco\",\n          \"marginTop\": 20,\n        }\n      }\n    />\n    <sketch_text\n      style={\n        Object {\n          \"color\": \"white\",\n          \"fontFamily\": \"Monaco\",\n          \"marginTop\": 20,\n        }\n      }\n    >\n      Script.runInThisContext\n    </sketch_text>\n    <sketch_text\n      style={\n        Object {\n          \"color\": \"white\",\n          \"fontFamily\": \"Monaco\",\n          \"marginTop\": 20,\n        }\n      }\n    >\n      REPLServer.defaultEval\n    </sketch_text>\n    <sketch_text\n      style={\n        Object {\n          \"color\": \"white\",\n          \"fontFamily\": \"Monaco\",\n          \"marginTop\": 20,\n        }\n      }\n    >\n      bound\n    </sketch_text>\n    <sketch_text\n      style={\n        Object {\n          \"color\": \"white\",\n          \"fontFamily\": \"Monaco\",\n          \"marginTop\": 20,\n        }\n      }\n    >\n      REPLServer.runBound [as eval]\n    </sketch_text>\n    <sketch_text\n      style={\n        Object {\n          \"color\": \"white\",\n          \"fontFamily\": \"Monaco\",\n          \"marginTop\": 20,\n        }\n      }\n    >\n      REPLServer.onLine\n    </sketch_text>\n    <sketch_text\n      style={\n        Object {\n          \"color\": \"white\",\n          \"fontFamily\": \"Monaco\",\n          \"marginTop\": 20,\n        }\n      }\n    >\n      REPLServer.emit\n    </sketch_text>\n    <sketch_text\n      style={\n        Object {\n          \"color\": \"white\",\n          \"fontFamily\": \"Monaco\",\n          \"marginTop\": 20,\n        }\n      }\n    >\n      REPLServer.emit\n    </sketch_text>\n    <sketch_text\n      style={\n        Object {\n          \"color\": \"white\",\n          \"fontFamily\": \"Monaco\",\n          \"marginTop\": 20,\n        }\n      }\n    >\n      REPLServer.Interface._onLine\n    </sketch_text>\n    <sketch_text\n      style={\n        Object {\n          \"color\": \"white\",\n          \"fontFamily\": \"Monaco\",\n          \"marginTop\": 20,\n        }\n      }\n    >\n      REPLServer.Interface._line\n    </sketch_text>\n  </sketch_view>\n</sketch_view>\n`;\n\nexports[`<RedBox /> renders string errors 1`] = `\n<sketch_view\n  name=\"RedBox\"\n  style={\n    Object {\n      \"backgroundColor\": \"rgb(204, 0, 0)\",\n      \"paddingBottom\": 10,\n      \"paddingLeft\": 10,\n      \"paddingRight\": 10,\n      \"paddingTop\": 10,\n      \"width\": 480,\n    }\n  }\n>\n  <sketch_text\n    name=\"Message\"\n    style={\n      Object {\n        \"color\": \"white\",\n        \"fontSize\": 16,\n        \"fontWeight\": \"bold\",\n        \"lineHeight\": 19.2,\n      }\n    }\n  >\n    Error: String only error\n  </sketch_text>\n</sketch_view>\n`;\n"
  },
  {
    "path": "__tests__/jest/components/__snapshots__/Svg.tsx.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`<Svg /> also works when child is directly imported 1`] = `\n<sketch_svg\n  height=\"447\"\n  preserveAspectRatio=\"xMidYMid meet\"\n  viewBox=\"0 0 494 447\"\n  width=\"494\"\n  xmlns=\"http://www.w3.org/2000/svg\"\n>\n  <svg_g\n    fill=\"none\"\n    fillRule=\"evenodd\"\n  >\n    <svg_path\n      d=\"M247 447L0 160 107 15 247 0l140 15 107 145\"\n      fill=\"#FFAE00\"\n    />\n    <svg_path\n      d=\"M247 447L0 160h494\"\n      fill=\"#EC6C00\"\n    />\n    <svg_path\n      d=\"M247 447L100 160h294\"\n      fill=\"#FFAE00\"\n    />\n    <svg_path\n      d=\"M247 0L100 160h294\"\n      fill=\"#FFEFB4\"\n    />\n    <svg_path\n      d=\"M107 15L52 88 0 160h101M387 15l55 73 52 72H393\"\n      fill=\"#FFAE00\"\n    />\n    <svg_path\n      d=\"M107 15l-7 145L247 0m140 15l7 145L247 0\"\n      fill=\"#FED305\"\n    />\n  </svg_g>\n</sketch_svg>\n`;\n\nexports[`<Svg /> passes its children 1`] = `\n<sketch_svg\n  height=\"447\"\n  preserveAspectRatio=\"xMidYMid meet\"\n  viewBox=\"0 0 494 447\"\n  width=\"494\"\n  xmlns=\"http://www.w3.org/2000/svg\"\n>\n  <svg_g\n    fill=\"none\"\n    fillRule=\"evenodd\"\n  >\n    <svg_path\n      d=\"M247 447L0 160 107 15 247 0l140 15 107 145\"\n      fill=\"#FFAE00\"\n    />\n    <svg_path\n      d=\"M247 447L0 160h494\"\n      fill=\"#EC6C00\"\n    />\n    <svg_path\n      d=\"M247 447L100 160h294\"\n      fill=\"#FFAE00\"\n    />\n    <svg_path\n      d=\"M247 0L100 160h294\"\n      fill=\"#FFEFB4\"\n    />\n    <svg_path\n      d=\"M107 15L52 88 0 160h101M387 15l55 73 52 72H393\"\n      fill=\"#FFAE00\"\n    />\n    <svg_path\n      d=\"M107 15l-7 145L247 0m140 15l7 145L247 0\"\n      fill=\"#FED305\"\n    />\n  </svg_g>\n</sketch_svg>\n`;\n"
  },
  {
    "path": "__tests__/jest/components/__snapshots__/Text.tsx.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`<Text /> name defaults to Text 1`] = `<sketch_text />`;\n\nexports[`<Text /> name passes its name 1`] = `\n<sketch_text\n  name=\"foo\"\n/>\n`;\n\nexports[`<Text /> passes its children 1`] = `\n<sketch_text>\n  foo\n</sketch_text>\n`;\n\nexports[`<Text /> style accepts a StyleSheet ordinal 1`] = `\n<sketch_text\n  style={\n    Object {\n      \"flex\": 1,\n    }\n  }\n/>\n`;\n\nexports[`<Text /> style accepts a plain object 1`] = `\n<sketch_text\n  style={\n    Object {\n      \"flex\": 1,\n    }\n  }\n/>\n`;\n\nexports[`<Text /> style accepts an array of plain objects and/or StyleSheet ordinals 1`] = `\n<sketch_text\n  style={\n    Object {\n      \"flex\": 1,\n      \"flexGrow\": 1,\n    }\n  }\n/>\n`;\n"
  },
  {
    "path": "__tests__/jest/components/__snapshots__/View.tsx.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`<View /> name defaults to View 1`] = `\n<sketch_view\n  name=\"View\"\n/>\n`;\n\nexports[`<View /> name passes its name 1`] = `\n<sketch_view\n  name=\"foo\"\n/>\n`;\n\nexports[`<View /> passes its children 1`] = `\n<sketch_view\n  name=\"View\"\n>\n  foo\n</sketch_view>\n`;\n\nexports[`<View /> style accepts a StyleSheet ordinal 1`] = `\n<sketch_view\n  name=\"View\"\n  style={\n    Object {\n      \"flex\": 1,\n    }\n  }\n/>\n`;\n\nexports[`<View /> style accepts a plain object 1`] = `\n<sketch_view\n  name=\"View\"\n  style={\n    Object {\n      \"flex\": 1,\n    }\n  }\n/>\n`;\n\nexports[`<View /> style accepts an array of plain objects and/or StyleSheet ordinals 1`] = `\n<sketch_view\n  name=\"View\"\n  style={\n    Object {\n      \"flex\": 1,\n      \"flexGrow\": 1,\n    }\n  }\n/>\n`;\n"
  },
  {
    "path": "__tests__/jest/components/nodeImpl/Svg.tsx",
    "content": "import * as React from 'react';\n\nimport * as ReactSketch from '../../../../src';\nimport Svg from '../../../../src/components/Svg';\n\njest.mock('../../../../src/jsonUtils/models', () => ({\n  ...require.requireActual('../../../../src/jsonUtils/models'),\n  generateID: jest.fn((seed) => (seed ? `${seed}mockID` : 'mockID')),\n}));\n\ndescribe('node <Svg />', () => {\n  it('generates the json for an svg', () => {\n    class SVGElement extends React.Component {\n      render() {\n        return (\n          <Svg xmlns=\"http://www.w3.org/2000/svg\" width=\"494\" height=\"447\" viewBox=\"0 0 494 447\">\n            <Svg.Path fill=\"#FFAE00\" d=\"M247 447L0 160 107 15 247 0l140 15 107 145\" />\n            <Svg.Path fill=\"#EC6C00\" d=\"M247 447L0 160h494\" />\n            <Svg.Path fill=\"#FFAE00\" d=\"M247 447L100 160h294\" />\n            <Svg.Path fill=\"#FFEFB4\" d=\"M247 0L100 160h294\" />\n            <Svg.Path fill=\"#FFAE00\" d=\"M107 15L52 88 0 160h101M387 15l55 73 52 72H393\" />\n            <Svg.Path fill=\"#FED305\" d=\"M107 15l-7 145L247 0m140 15l7 145L247 0\" />\n          </Svg>\n        );\n      }\n    }\n\n    expect(ReactSketch.renderToJSON(<SVGElement />)).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "__tests__/jest/components/nodeImpl/__snapshots__/Svg.tsx.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`node <Svg /> generates the json for an svg 1`] = `\nObject {\n  \"_class\": \"group\",\n  \"booleanOperation\": -1,\n  \"do_objectID\": \"mockID\",\n  \"exportOptions\": Object {\n    \"_class\": \"exportOptions\",\n    \"exportFormats\": Array [],\n    \"includedLayerIds\": Array [],\n    \"layerOptions\": 0,\n    \"shouldTrim\": false,\n  },\n  \"frame\": Object {\n    \"_class\": \"rect\",\n    \"constrainProportions\": false,\n    \"height\": 447,\n    \"width\": 494,\n    \"x\": 0,\n    \"y\": 0,\n  },\n  \"hasClickThrough\": false,\n  \"isFixedToViewport\": false,\n  \"isFlippedHorizontal\": false,\n  \"isFlippedVertical\": false,\n  \"isLocked\": false,\n  \"isVisible\": true,\n  \"layerListExpandedType\": 2,\n  \"layers\": Array [\n    Object {\n      \"_class\": \"group\",\n      \"booleanOperation\": -1,\n      \"do_objectID\": \"mockID\",\n      \"exportOptions\": Object {\n        \"_class\": \"exportOptions\",\n        \"exportFormats\": Array [],\n        \"includedLayerIds\": Array [],\n        \"layerOptions\": 0,\n        \"shouldTrim\": false,\n      },\n      \"frame\": Object {\n        \"_class\": \"rect\",\n        \"constrainProportions\": false,\n        \"height\": 447,\n        \"width\": 494,\n        \"x\": 0,\n        \"y\": 0,\n      },\n      \"hasClickThrough\": false,\n      \"isFixedToViewport\": false,\n      \"isFlippedHorizontal\": false,\n      \"isFlippedVertical\": false,\n      \"isLocked\": false,\n      \"isVisible\": true,\n      \"layerListExpandedType\": 2,\n      \"layers\": Array [\n        Object {\n          \"_class\": \"shapeGroup\",\n          \"booleanOperation\": -1,\n          \"clippingMaskMode\": 0,\n          \"do_objectID\": \"mockID\",\n          \"exportOptions\": Object {\n            \"_class\": \"exportOptions\",\n            \"exportFormats\": Array [],\n            \"includedLayerIds\": Array [],\n            \"layerOptions\": 0,\n            \"shouldTrim\": false,\n          },\n          \"frame\": Object {\n            \"_class\": \"rect\",\n            \"constrainProportions\": false,\n            \"height\": 447,\n            \"width\": 494,\n            \"x\": 0,\n            \"y\": 0,\n          },\n          \"hasClickThrough\": false,\n          \"hasClippingMask\": false,\n          \"isFixedToViewport\": false,\n          \"isFlippedHorizontal\": false,\n          \"isFlippedVertical\": false,\n          \"isLocked\": false,\n          \"isVisible\": true,\n          \"layerListExpandedType\": 0,\n          \"layers\": Array [\n            Object {\n              \"_class\": \"shapePath\",\n              \"booleanOperation\": -1,\n              \"do_objectID\": \"mockID\",\n              \"edited\": false,\n              \"exportOptions\": Object {\n                \"_class\": \"exportOptions\",\n                \"exportFormats\": Array [],\n                \"includedLayerIds\": Array [],\n                \"layerOptions\": 0,\n                \"shouldTrim\": false,\n              },\n              \"frame\": Object {\n                \"_class\": \"rect\",\n                \"constrainProportions\": false,\n                \"height\": 447,\n                \"width\": 494,\n                \"x\": 0,\n                \"y\": 0,\n              },\n              \"isClosed\": false,\n              \"isFixedToViewport\": false,\n              \"isFlippedHorizontal\": false,\n              \"isFlippedVertical\": false,\n              \"isLocked\": false,\n              \"isVisible\": true,\n              \"layerListExpandedType\": 0,\n              \"name\": \"Path\",\n              \"nameIsFixed\": false,\n              \"pointRadiusBehaviour\": 1,\n              \"points\": Array [\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0.5, 1}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0.5, 1}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0.5, 1}\",\n                },\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0, 0.3579418344519016}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0, 0.3579418344519016}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0, 0.3579418344519016}\",\n                },\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0.2165991902834008, 0.03355704697986577}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0.2165991902834008, 0.03355704697986577}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0.2165991902834008, 0.03355704697986577}\",\n                },\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0.5, 0}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0.5, 0}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0.5, 0}\",\n                },\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0.7834008097165992, 0.03355704697986577}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0.7834008097165992, 0.03355704697986577}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0.7834008097165992, 0.03355704697986577}\",\n                },\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{1, 0.3579418344519016}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{1, 0.3579418344519016}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{1, 0.3579418344519016}\",\n                },\n              ],\n              \"resizingConstraint\": 63,\n              \"resizingType\": 0,\n              \"rotation\": 0,\n              \"shouldBreakMaskChain\": false,\n            },\n          ],\n          \"name\": \"ShapeGroup\",\n          \"nameIsFixed\": false,\n          \"resizingConstraint\": 63,\n          \"resizingType\": 0,\n          \"rotation\": 0,\n          \"shouldBreakMaskChain\": false,\n          \"style\": Object {\n            \"_class\": \"style\",\n            \"borderOptions\": Object {\n              \"_class\": \"borderOptions\",\n              \"dashPattern\": Array [],\n              \"isEnabled\": false,\n              \"lineCapStyle\": 0,\n              \"lineJoinStyle\": 0,\n            },\n            \"colorControls\": Object {\n              \"_class\": \"colorControls\",\n              \"brightness\": 1,\n              \"contrast\": 1,\n              \"hue\": 1,\n              \"isEnabled\": false,\n              \"saturation\": 1,\n            },\n            \"endMarkerType\": 0,\n            \"fills\": Array [\n              Object {\n                \"_class\": \"fill\",\n                \"color\": Object {\n                  \"_class\": \"color\",\n                  \"alpha\": 1,\n                  \"blue\": 0,\n                  \"green\": 0.6823529411764706,\n                  \"red\": 1,\n                },\n                \"contextSettings\": Object {\n                  \"_class\": \"graphicsContextSettings\",\n                  \"blendMode\": 0,\n                  \"opacity\": 1,\n                },\n                \"fillType\": 0,\n                \"gradient\": Object {\n                  \"_class\": \"gradient\",\n                  \"elipseLength\": 0,\n                  \"from\": \"{0.5, 0}\",\n                  \"gradientType\": 0,\n                  \"stops\": Array [\n                    Object {\n                      \"_class\": \"gradientStop\",\n                      \"color\": Object {\n                        \"_class\": \"color\",\n                        \"alpha\": 1,\n                        \"blue\": 1,\n                        \"green\": 1,\n                        \"red\": 1,\n                      },\n                      \"position\": 0,\n                    },\n                    Object {\n                      \"_class\": \"gradientStop\",\n                      \"color\": Object {\n                        \"_class\": \"color\",\n                        \"alpha\": 1,\n                        \"blue\": 0,\n                        \"green\": 0,\n                        \"red\": 0,\n                      },\n                      \"position\": 1,\n                    },\n                  ],\n                  \"to\": \"{0.5, 1}\",\n                },\n                \"isEnabled\": true,\n                \"noiseIndex\": 0,\n                \"noiseIntensity\": 0,\n                \"patternFillType\": 1,\n                \"patternTileScale\": 1,\n              },\n            ],\n            \"innerShadows\": Array [],\n            \"miterLimit\": 10,\n            \"shadows\": Array [],\n            \"startMarkerType\": 0,\n            \"windingRule\": 1,\n          },\n          \"windingRule\": 1,\n        },\n        Object {\n          \"_class\": \"shapeGroup\",\n          \"booleanOperation\": -1,\n          \"clippingMaskMode\": 0,\n          \"do_objectID\": \"mockID\",\n          \"exportOptions\": Object {\n            \"_class\": \"exportOptions\",\n            \"exportFormats\": Array [],\n            \"includedLayerIds\": Array [],\n            \"layerOptions\": 0,\n            \"shouldTrim\": false,\n          },\n          \"frame\": Object {\n            \"_class\": \"rect\",\n            \"constrainProportions\": false,\n            \"height\": 287,\n            \"width\": 494,\n            \"x\": 0,\n            \"y\": 160,\n          },\n          \"hasClickThrough\": false,\n          \"hasClippingMask\": false,\n          \"isFixedToViewport\": false,\n          \"isFlippedHorizontal\": false,\n          \"isFlippedVertical\": false,\n          \"isLocked\": false,\n          \"isVisible\": true,\n          \"layerListExpandedType\": 0,\n          \"layers\": Array [\n            Object {\n              \"_class\": \"shapePath\",\n              \"booleanOperation\": -1,\n              \"do_objectID\": \"mockID\",\n              \"edited\": false,\n              \"exportOptions\": Object {\n                \"_class\": \"exportOptions\",\n                \"exportFormats\": Array [],\n                \"includedLayerIds\": Array [],\n                \"layerOptions\": 0,\n                \"shouldTrim\": false,\n              },\n              \"frame\": Object {\n                \"_class\": \"rect\",\n                \"constrainProportions\": false,\n                \"height\": 287,\n                \"width\": 494,\n                \"x\": 0,\n                \"y\": 0,\n              },\n              \"isClosed\": false,\n              \"isFixedToViewport\": false,\n              \"isFlippedHorizontal\": false,\n              \"isFlippedVertical\": false,\n              \"isLocked\": false,\n              \"isVisible\": true,\n              \"layerListExpandedType\": 0,\n              \"name\": \"Path\",\n              \"nameIsFixed\": false,\n              \"pointRadiusBehaviour\": 1,\n              \"points\": Array [\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0.5, 1}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0.5, 1}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0.5, 1}\",\n                },\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0, 0}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0, 0}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0, 0}\",\n                },\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{1, 0}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{1, 0}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{1, 0}\",\n                },\n              ],\n              \"resizingConstraint\": 63,\n              \"resizingType\": 0,\n              \"rotation\": 0,\n              \"shouldBreakMaskChain\": false,\n            },\n          ],\n          \"name\": \"ShapeGroup\",\n          \"nameIsFixed\": false,\n          \"resizingConstraint\": 63,\n          \"resizingType\": 0,\n          \"rotation\": 0,\n          \"shouldBreakMaskChain\": false,\n          \"style\": Object {\n            \"_class\": \"style\",\n            \"borderOptions\": Object {\n              \"_class\": \"borderOptions\",\n              \"dashPattern\": Array [],\n              \"isEnabled\": false,\n              \"lineCapStyle\": 0,\n              \"lineJoinStyle\": 0,\n            },\n            \"colorControls\": Object {\n              \"_class\": \"colorControls\",\n              \"brightness\": 1,\n              \"contrast\": 1,\n              \"hue\": 1,\n              \"isEnabled\": false,\n              \"saturation\": 1,\n            },\n            \"endMarkerType\": 0,\n            \"fills\": Array [\n              Object {\n                \"_class\": \"fill\",\n                \"color\": Object {\n                  \"_class\": \"color\",\n                  \"alpha\": 1,\n                  \"blue\": 0,\n                  \"green\": 0.4235294117647059,\n                  \"red\": 0.9254901960784314,\n                },\n                \"contextSettings\": Object {\n                  \"_class\": \"graphicsContextSettings\",\n                  \"blendMode\": 0,\n                  \"opacity\": 1,\n                },\n                \"fillType\": 0,\n                \"gradient\": Object {\n                  \"_class\": \"gradient\",\n                  \"elipseLength\": 0,\n                  \"from\": \"{0.5, 0}\",\n                  \"gradientType\": 0,\n                  \"stops\": Array [\n                    Object {\n                      \"_class\": \"gradientStop\",\n                      \"color\": Object {\n                        \"_class\": \"color\",\n                        \"alpha\": 1,\n                        \"blue\": 1,\n                        \"green\": 1,\n                        \"red\": 1,\n                      },\n                      \"position\": 0,\n                    },\n                    Object {\n                      \"_class\": \"gradientStop\",\n                      \"color\": Object {\n                        \"_class\": \"color\",\n                        \"alpha\": 1,\n                        \"blue\": 0,\n                        \"green\": 0,\n                        \"red\": 0,\n                      },\n                      \"position\": 1,\n                    },\n                  ],\n                  \"to\": \"{0.5, 1}\",\n                },\n                \"isEnabled\": true,\n                \"noiseIndex\": 0,\n                \"noiseIntensity\": 0,\n                \"patternFillType\": 1,\n                \"patternTileScale\": 1,\n              },\n            ],\n            \"innerShadows\": Array [],\n            \"miterLimit\": 10,\n            \"shadows\": Array [],\n            \"startMarkerType\": 0,\n            \"windingRule\": 1,\n          },\n          \"windingRule\": 1,\n        },\n        Object {\n          \"_class\": \"shapeGroup\",\n          \"booleanOperation\": -1,\n          \"clippingMaskMode\": 0,\n          \"do_objectID\": \"mockID\",\n          \"exportOptions\": Object {\n            \"_class\": \"exportOptions\",\n            \"exportFormats\": Array [],\n            \"includedLayerIds\": Array [],\n            \"layerOptions\": 0,\n            \"shouldTrim\": false,\n          },\n          \"frame\": Object {\n            \"_class\": \"rect\",\n            \"constrainProportions\": false,\n            \"height\": 287,\n            \"width\": 294,\n            \"x\": 100,\n            \"y\": 160,\n          },\n          \"hasClickThrough\": false,\n          \"hasClippingMask\": false,\n          \"isFixedToViewport\": false,\n          \"isFlippedHorizontal\": false,\n          \"isFlippedVertical\": false,\n          \"isLocked\": false,\n          \"isVisible\": true,\n          \"layerListExpandedType\": 0,\n          \"layers\": Array [\n            Object {\n              \"_class\": \"shapePath\",\n              \"booleanOperation\": -1,\n              \"do_objectID\": \"mockID\",\n              \"edited\": false,\n              \"exportOptions\": Object {\n                \"_class\": \"exportOptions\",\n                \"exportFormats\": Array [],\n                \"includedLayerIds\": Array [],\n                \"layerOptions\": 0,\n                \"shouldTrim\": false,\n              },\n              \"frame\": Object {\n                \"_class\": \"rect\",\n                \"constrainProportions\": false,\n                \"height\": 287,\n                \"width\": 294,\n                \"x\": 0,\n                \"y\": 0,\n              },\n              \"isClosed\": false,\n              \"isFixedToViewport\": false,\n              \"isFlippedHorizontal\": false,\n              \"isFlippedVertical\": false,\n              \"isLocked\": false,\n              \"isVisible\": true,\n              \"layerListExpandedType\": 0,\n              \"name\": \"Path\",\n              \"nameIsFixed\": false,\n              \"pointRadiusBehaviour\": 1,\n              \"points\": Array [\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0.5, 1}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0.5, 1}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0.5, 1}\",\n                },\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0, 0}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0, 0}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0, 0}\",\n                },\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{1, 0}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{1, 0}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{1, 0}\",\n                },\n              ],\n              \"resizingConstraint\": 63,\n              \"resizingType\": 0,\n              \"rotation\": 0,\n              \"shouldBreakMaskChain\": false,\n            },\n          ],\n          \"name\": \"ShapeGroup\",\n          \"nameIsFixed\": false,\n          \"resizingConstraint\": 63,\n          \"resizingType\": 0,\n          \"rotation\": 0,\n          \"shouldBreakMaskChain\": false,\n          \"style\": Object {\n            \"_class\": \"style\",\n            \"borderOptions\": Object {\n              \"_class\": \"borderOptions\",\n              \"dashPattern\": Array [],\n              \"isEnabled\": false,\n              \"lineCapStyle\": 0,\n              \"lineJoinStyle\": 0,\n            },\n            \"colorControls\": Object {\n              \"_class\": \"colorControls\",\n              \"brightness\": 1,\n              \"contrast\": 1,\n              \"hue\": 1,\n              \"isEnabled\": false,\n              \"saturation\": 1,\n            },\n            \"endMarkerType\": 0,\n            \"fills\": Array [\n              Object {\n                \"_class\": \"fill\",\n                \"color\": Object {\n                  \"_class\": \"color\",\n                  \"alpha\": 1,\n                  \"blue\": 0,\n                  \"green\": 0.6823529411764706,\n                  \"red\": 1,\n                },\n                \"contextSettings\": Object {\n                  \"_class\": \"graphicsContextSettings\",\n                  \"blendMode\": 0,\n                  \"opacity\": 1,\n                },\n                \"fillType\": 0,\n                \"gradient\": Object {\n                  \"_class\": \"gradient\",\n                  \"elipseLength\": 0,\n                  \"from\": \"{0.5, 0}\",\n                  \"gradientType\": 0,\n                  \"stops\": Array [\n                    Object {\n                      \"_class\": \"gradientStop\",\n                      \"color\": Object {\n                        \"_class\": \"color\",\n                        \"alpha\": 1,\n                        \"blue\": 1,\n                        \"green\": 1,\n                        \"red\": 1,\n                      },\n                      \"position\": 0,\n                    },\n                    Object {\n                      \"_class\": \"gradientStop\",\n                      \"color\": Object {\n                        \"_class\": \"color\",\n                        \"alpha\": 1,\n                        \"blue\": 0,\n                        \"green\": 0,\n                        \"red\": 0,\n                      },\n                      \"position\": 1,\n                    },\n                  ],\n                  \"to\": \"{0.5, 1}\",\n                },\n                \"isEnabled\": true,\n                \"noiseIndex\": 0,\n                \"noiseIntensity\": 0,\n                \"patternFillType\": 1,\n                \"patternTileScale\": 1,\n              },\n            ],\n            \"innerShadows\": Array [],\n            \"miterLimit\": 10,\n            \"shadows\": Array [],\n            \"startMarkerType\": 0,\n            \"windingRule\": 1,\n          },\n          \"windingRule\": 1,\n        },\n        Object {\n          \"_class\": \"shapeGroup\",\n          \"booleanOperation\": -1,\n          \"clippingMaskMode\": 0,\n          \"do_objectID\": \"mockID\",\n          \"exportOptions\": Object {\n            \"_class\": \"exportOptions\",\n            \"exportFormats\": Array [],\n            \"includedLayerIds\": Array [],\n            \"layerOptions\": 0,\n            \"shouldTrim\": false,\n          },\n          \"frame\": Object {\n            \"_class\": \"rect\",\n            \"constrainProportions\": false,\n            \"height\": 160,\n            \"width\": 294,\n            \"x\": 100,\n            \"y\": 0,\n          },\n          \"hasClickThrough\": false,\n          \"hasClippingMask\": false,\n          \"isFixedToViewport\": false,\n          \"isFlippedHorizontal\": false,\n          \"isFlippedVertical\": false,\n          \"isLocked\": false,\n          \"isVisible\": true,\n          \"layerListExpandedType\": 0,\n          \"layers\": Array [\n            Object {\n              \"_class\": \"shapePath\",\n              \"booleanOperation\": -1,\n              \"do_objectID\": \"mockID\",\n              \"edited\": false,\n              \"exportOptions\": Object {\n                \"_class\": \"exportOptions\",\n                \"exportFormats\": Array [],\n                \"includedLayerIds\": Array [],\n                \"layerOptions\": 0,\n                \"shouldTrim\": false,\n              },\n              \"frame\": Object {\n                \"_class\": \"rect\",\n                \"constrainProportions\": false,\n                \"height\": 160,\n                \"width\": 294,\n                \"x\": 0,\n                \"y\": 0,\n              },\n              \"isClosed\": false,\n              \"isFixedToViewport\": false,\n              \"isFlippedHorizontal\": false,\n              \"isFlippedVertical\": false,\n              \"isLocked\": false,\n              \"isVisible\": true,\n              \"layerListExpandedType\": 0,\n              \"name\": \"Path\",\n              \"nameIsFixed\": false,\n              \"pointRadiusBehaviour\": 1,\n              \"points\": Array [\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0.5, 0}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0.5, 0}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0.5, 0}\",\n                },\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0, 1}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0, 1}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0, 1}\",\n                },\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{1, 1}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{1, 1}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{1, 1}\",\n                },\n              ],\n              \"resizingConstraint\": 63,\n              \"resizingType\": 0,\n              \"rotation\": 0,\n              \"shouldBreakMaskChain\": false,\n            },\n          ],\n          \"name\": \"ShapeGroup\",\n          \"nameIsFixed\": false,\n          \"resizingConstraint\": 63,\n          \"resizingType\": 0,\n          \"rotation\": 0,\n          \"shouldBreakMaskChain\": false,\n          \"style\": Object {\n            \"_class\": \"style\",\n            \"borderOptions\": Object {\n              \"_class\": \"borderOptions\",\n              \"dashPattern\": Array [],\n              \"isEnabled\": false,\n              \"lineCapStyle\": 0,\n              \"lineJoinStyle\": 0,\n            },\n            \"colorControls\": Object {\n              \"_class\": \"colorControls\",\n              \"brightness\": 1,\n              \"contrast\": 1,\n              \"hue\": 1,\n              \"isEnabled\": false,\n              \"saturation\": 1,\n            },\n            \"endMarkerType\": 0,\n            \"fills\": Array [\n              Object {\n                \"_class\": \"fill\",\n                \"color\": Object {\n                  \"_class\": \"color\",\n                  \"alpha\": 1,\n                  \"blue\": 0.7058823529411765,\n                  \"green\": 0.9372549019607843,\n                  \"red\": 1,\n                },\n                \"contextSettings\": Object {\n                  \"_class\": \"graphicsContextSettings\",\n                  \"blendMode\": 0,\n                  \"opacity\": 1,\n                },\n                \"fillType\": 0,\n                \"gradient\": Object {\n                  \"_class\": \"gradient\",\n                  \"elipseLength\": 0,\n                  \"from\": \"{0.5, 0}\",\n                  \"gradientType\": 0,\n                  \"stops\": Array [\n                    Object {\n                      \"_class\": \"gradientStop\",\n                      \"color\": Object {\n                        \"_class\": \"color\",\n                        \"alpha\": 1,\n                        \"blue\": 1,\n                        \"green\": 1,\n                        \"red\": 1,\n                      },\n                      \"position\": 0,\n                    },\n                    Object {\n                      \"_class\": \"gradientStop\",\n                      \"color\": Object {\n                        \"_class\": \"color\",\n                        \"alpha\": 1,\n                        \"blue\": 0,\n                        \"green\": 0,\n                        \"red\": 0,\n                      },\n                      \"position\": 1,\n                    },\n                  ],\n                  \"to\": \"{0.5, 1}\",\n                },\n                \"isEnabled\": true,\n                \"noiseIndex\": 0,\n                \"noiseIntensity\": 0,\n                \"patternFillType\": 1,\n                \"patternTileScale\": 1,\n              },\n            ],\n            \"innerShadows\": Array [],\n            \"miterLimit\": 10,\n            \"shadows\": Array [],\n            \"startMarkerType\": 0,\n            \"windingRule\": 1,\n          },\n          \"windingRule\": 1,\n        },\n        Object {\n          \"_class\": \"shapeGroup\",\n          \"booleanOperation\": -1,\n          \"clippingMaskMode\": 0,\n          \"do_objectID\": \"mockID\",\n          \"exportOptions\": Object {\n            \"_class\": \"exportOptions\",\n            \"exportFormats\": Array [],\n            \"includedLayerIds\": Array [],\n            \"layerOptions\": 0,\n            \"shouldTrim\": false,\n          },\n          \"frame\": Object {\n            \"_class\": \"rect\",\n            \"constrainProportions\": false,\n            \"height\": 145,\n            \"width\": 494,\n            \"x\": 0,\n            \"y\": 15,\n          },\n          \"hasClickThrough\": false,\n          \"hasClippingMask\": false,\n          \"isFixedToViewport\": false,\n          \"isFlippedHorizontal\": false,\n          \"isFlippedVertical\": false,\n          \"isLocked\": false,\n          \"isVisible\": true,\n          \"layerListExpandedType\": 0,\n          \"layers\": Array [\n            Object {\n              \"_class\": \"shapePath\",\n              \"booleanOperation\": -1,\n              \"do_objectID\": \"mockID\",\n              \"edited\": false,\n              \"exportOptions\": Object {\n                \"_class\": \"exportOptions\",\n                \"exportFormats\": Array [],\n                \"includedLayerIds\": Array [],\n                \"layerOptions\": 0,\n                \"shouldTrim\": false,\n              },\n              \"frame\": Object {\n                \"_class\": \"rect\",\n                \"constrainProportions\": false,\n                \"height\": 145,\n                \"width\": 494,\n                \"x\": 0,\n                \"y\": 0,\n              },\n              \"isClosed\": false,\n              \"isFixedToViewport\": false,\n              \"isFlippedHorizontal\": false,\n              \"isFlippedVertical\": false,\n              \"isLocked\": false,\n              \"isVisible\": true,\n              \"layerListExpandedType\": 0,\n              \"name\": \"Path\",\n              \"nameIsFixed\": false,\n              \"pointRadiusBehaviour\": 1,\n              \"points\": Array [\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0.2165991902834008, 0}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0.2165991902834008, 0}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0.2165991902834008, 0}\",\n                },\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0.10526315789473684, 0.503448275862069}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0.10526315789473684, 0.503448275862069}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0.10526315789473684, 0.503448275862069}\",\n                },\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0, 1}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0, 1}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0, 1}\",\n                },\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0.20445344129554655, 1}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0.20445344129554655, 1}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0.20445344129554655, 1}\",\n                },\n              ],\n              \"resizingConstraint\": 63,\n              \"resizingType\": 0,\n              \"rotation\": 0,\n              \"shouldBreakMaskChain\": false,\n            },\n            Object {\n              \"_class\": \"shapePath\",\n              \"booleanOperation\": -1,\n              \"do_objectID\": \"mockID\",\n              \"edited\": false,\n              \"exportOptions\": Object {\n                \"_class\": \"exportOptions\",\n                \"exportFormats\": Array [],\n                \"includedLayerIds\": Array [],\n                \"layerOptions\": 0,\n                \"shouldTrim\": false,\n              },\n              \"frame\": Object {\n                \"_class\": \"rect\",\n                \"constrainProportions\": false,\n                \"height\": 145,\n                \"width\": 494,\n                \"x\": 0,\n                \"y\": 0,\n              },\n              \"isClosed\": false,\n              \"isFixedToViewport\": false,\n              \"isFlippedHorizontal\": false,\n              \"isFlippedVertical\": false,\n              \"isLocked\": false,\n              \"isVisible\": true,\n              \"layerListExpandedType\": 0,\n              \"name\": \"Path\",\n              \"nameIsFixed\": false,\n              \"pointRadiusBehaviour\": 1,\n              \"points\": Array [\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0.7834008097165992, 0}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0.7834008097165992, 0}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0.7834008097165992, 0}\",\n                },\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0.8947368421052632, 0.503448275862069}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0.8947368421052632, 0.503448275862069}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0.8947368421052632, 0.503448275862069}\",\n                },\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{1, 1}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{1, 1}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{1, 1}\",\n                },\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0.7955465587044535, 1}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0.7955465587044535, 1}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0.7955465587044535, 1}\",\n                },\n              ],\n              \"resizingConstraint\": 63,\n              \"resizingType\": 0,\n              \"rotation\": 0,\n              \"shouldBreakMaskChain\": false,\n            },\n          ],\n          \"name\": \"ShapeGroup\",\n          \"nameIsFixed\": false,\n          \"resizingConstraint\": 63,\n          \"resizingType\": 0,\n          \"rotation\": 0,\n          \"shouldBreakMaskChain\": false,\n          \"style\": Object {\n            \"_class\": \"style\",\n            \"borderOptions\": Object {\n              \"_class\": \"borderOptions\",\n              \"dashPattern\": Array [],\n              \"isEnabled\": false,\n              \"lineCapStyle\": 0,\n              \"lineJoinStyle\": 0,\n            },\n            \"colorControls\": Object {\n              \"_class\": \"colorControls\",\n              \"brightness\": 1,\n              \"contrast\": 1,\n              \"hue\": 1,\n              \"isEnabled\": false,\n              \"saturation\": 1,\n            },\n            \"endMarkerType\": 0,\n            \"fills\": Array [\n              Object {\n                \"_class\": \"fill\",\n                \"color\": Object {\n                  \"_class\": \"color\",\n                  \"alpha\": 1,\n                  \"blue\": 0,\n                  \"green\": 0.6823529411764706,\n                  \"red\": 1,\n                },\n                \"contextSettings\": Object {\n                  \"_class\": \"graphicsContextSettings\",\n                  \"blendMode\": 0,\n                  \"opacity\": 1,\n                },\n                \"fillType\": 0,\n                \"gradient\": Object {\n                  \"_class\": \"gradient\",\n                  \"elipseLength\": 0,\n                  \"from\": \"{0.5, 0}\",\n                  \"gradientType\": 0,\n                  \"stops\": Array [\n                    Object {\n                      \"_class\": \"gradientStop\",\n                      \"color\": Object {\n                        \"_class\": \"color\",\n                        \"alpha\": 1,\n                        \"blue\": 1,\n                        \"green\": 1,\n                        \"red\": 1,\n                      },\n                      \"position\": 0,\n                    },\n                    Object {\n                      \"_class\": \"gradientStop\",\n                      \"color\": Object {\n                        \"_class\": \"color\",\n                        \"alpha\": 1,\n                        \"blue\": 0,\n                        \"green\": 0,\n                        \"red\": 0,\n                      },\n                      \"position\": 1,\n                    },\n                  ],\n                  \"to\": \"{0.5, 1}\",\n                },\n                \"isEnabled\": true,\n                \"noiseIndex\": 0,\n                \"noiseIntensity\": 0,\n                \"patternFillType\": 1,\n                \"patternTileScale\": 1,\n              },\n            ],\n            \"innerShadows\": Array [],\n            \"miterLimit\": 10,\n            \"shadows\": Array [],\n            \"startMarkerType\": 0,\n            \"windingRule\": 1,\n          },\n          \"windingRule\": 1,\n        },\n        Object {\n          \"_class\": \"shapeGroup\",\n          \"booleanOperation\": -1,\n          \"clippingMaskMode\": 0,\n          \"do_objectID\": \"mockID\",\n          \"exportOptions\": Object {\n            \"_class\": \"exportOptions\",\n            \"exportFormats\": Array [],\n            \"includedLayerIds\": Array [],\n            \"layerOptions\": 0,\n            \"shouldTrim\": false,\n          },\n          \"frame\": Object {\n            \"_class\": \"rect\",\n            \"constrainProportions\": false,\n            \"height\": 160,\n            \"width\": 294,\n            \"x\": 100,\n            \"y\": 0,\n          },\n          \"hasClickThrough\": false,\n          \"hasClippingMask\": false,\n          \"isFixedToViewport\": false,\n          \"isFlippedHorizontal\": false,\n          \"isFlippedVertical\": false,\n          \"isLocked\": false,\n          \"isVisible\": true,\n          \"layerListExpandedType\": 0,\n          \"layers\": Array [\n            Object {\n              \"_class\": \"shapePath\",\n              \"booleanOperation\": -1,\n              \"do_objectID\": \"mockID\",\n              \"edited\": false,\n              \"exportOptions\": Object {\n                \"_class\": \"exportOptions\",\n                \"exportFormats\": Array [],\n                \"includedLayerIds\": Array [],\n                \"layerOptions\": 0,\n                \"shouldTrim\": false,\n              },\n              \"frame\": Object {\n                \"_class\": \"rect\",\n                \"constrainProportions\": false,\n                \"height\": 160,\n                \"width\": 294,\n                \"x\": 0,\n                \"y\": 0,\n              },\n              \"isClosed\": false,\n              \"isFixedToViewport\": false,\n              \"isFlippedHorizontal\": false,\n              \"isFlippedVertical\": false,\n              \"isLocked\": false,\n              \"isVisible\": true,\n              \"layerListExpandedType\": 0,\n              \"name\": \"Path\",\n              \"nameIsFixed\": false,\n              \"pointRadiusBehaviour\": 1,\n              \"points\": Array [\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0.023809523809523808, 0.09375}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0.023809523809523808, 0.09375}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0.023809523809523808, 0.09375}\",\n                },\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0, 1}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0, 1}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0, 1}\",\n                },\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0.5, 0}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0.5, 0}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0.5, 0}\",\n                },\n              ],\n              \"resizingConstraint\": 63,\n              \"resizingType\": 0,\n              \"rotation\": 0,\n              \"shouldBreakMaskChain\": false,\n            },\n            Object {\n              \"_class\": \"shapePath\",\n              \"booleanOperation\": -1,\n              \"do_objectID\": \"mockID\",\n              \"edited\": false,\n              \"exportOptions\": Object {\n                \"_class\": \"exportOptions\",\n                \"exportFormats\": Array [],\n                \"includedLayerIds\": Array [],\n                \"layerOptions\": 0,\n                \"shouldTrim\": false,\n              },\n              \"frame\": Object {\n                \"_class\": \"rect\",\n                \"constrainProportions\": false,\n                \"height\": 160,\n                \"width\": 294,\n                \"x\": 0,\n                \"y\": 0,\n              },\n              \"isClosed\": false,\n              \"isFixedToViewport\": false,\n              \"isFlippedHorizontal\": false,\n              \"isFlippedVertical\": false,\n              \"isLocked\": false,\n              \"isVisible\": true,\n              \"layerListExpandedType\": 0,\n              \"name\": \"Path\",\n              \"nameIsFixed\": false,\n              \"pointRadiusBehaviour\": 1,\n              \"points\": Array [\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0.9761904761904762, 0.09375}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0.9761904761904762, 0.09375}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0.9761904761904762, 0.09375}\",\n                },\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{1, 1}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{1, 1}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{1, 1}\",\n                },\n                Object {\n                  \"_class\": \"curvePoint\",\n                  \"cornerRadius\": 0,\n                  \"curveFrom\": \"{0.5, 0}\",\n                  \"curveMode\": 1,\n                  \"curveTo\": \"{0.5, 0}\",\n                  \"hasCurveFrom\": false,\n                  \"hasCurveTo\": false,\n                  \"point\": \"{0.5, 0}\",\n                },\n              ],\n              \"resizingConstraint\": 63,\n              \"resizingType\": 0,\n              \"rotation\": 0,\n              \"shouldBreakMaskChain\": false,\n            },\n          ],\n          \"name\": \"ShapeGroup\",\n          \"nameIsFixed\": false,\n          \"resizingConstraint\": 63,\n          \"resizingType\": 0,\n          \"rotation\": 0,\n          \"shouldBreakMaskChain\": false,\n          \"style\": Object {\n            \"_class\": \"style\",\n            \"borderOptions\": Object {\n              \"_class\": \"borderOptions\",\n              \"dashPattern\": Array [],\n              \"isEnabled\": false,\n              \"lineCapStyle\": 0,\n              \"lineJoinStyle\": 0,\n            },\n            \"colorControls\": Object {\n              \"_class\": \"colorControls\",\n              \"brightness\": 1,\n              \"contrast\": 1,\n              \"hue\": 1,\n              \"isEnabled\": false,\n              \"saturation\": 1,\n            },\n            \"endMarkerType\": 0,\n            \"fills\": Array [\n              Object {\n                \"_class\": \"fill\",\n                \"color\": Object {\n                  \"_class\": \"color\",\n                  \"alpha\": 1,\n                  \"blue\": 0.0196078431372549,\n                  \"green\": 0.8274509803921568,\n                  \"red\": 0.996078431372549,\n                },\n                \"contextSettings\": Object {\n                  \"_class\": \"graphicsContextSettings\",\n                  \"blendMode\": 0,\n                  \"opacity\": 1,\n                },\n                \"fillType\": 0,\n                \"gradient\": Object {\n                  \"_class\": \"gradient\",\n                  \"elipseLength\": 0,\n                  \"from\": \"{0.5, 0}\",\n                  \"gradientType\": 0,\n                  \"stops\": Array [\n                    Object {\n                      \"_class\": \"gradientStop\",\n                      \"color\": Object {\n                        \"_class\": \"color\",\n                        \"alpha\": 1,\n                        \"blue\": 1,\n                        \"green\": 1,\n                        \"red\": 1,\n                      },\n                      \"position\": 0,\n                    },\n                    Object {\n                      \"_class\": \"gradientStop\",\n                      \"color\": Object {\n                        \"_class\": \"color\",\n                        \"alpha\": 1,\n                        \"blue\": 0,\n                        \"green\": 0,\n                        \"red\": 0,\n                      },\n                      \"position\": 1,\n                    },\n                  ],\n                  \"to\": \"{0.5, 1}\",\n                },\n                \"isEnabled\": true,\n                \"noiseIndex\": 0,\n                \"noiseIntensity\": 0,\n                \"patternFillType\": 1,\n                \"patternTileScale\": 1,\n              },\n            ],\n            \"innerShadows\": Array [],\n            \"miterLimit\": 10,\n            \"shadows\": Array [],\n            \"startMarkerType\": 0,\n            \"windingRule\": 1,\n          },\n          \"windingRule\": 1,\n        },\n      ],\n      \"name\": \"Shape\",\n      \"nameIsFixed\": false,\n      \"resizingConstraint\": 63,\n      \"resizingType\": 0,\n      \"rotation\": 0,\n      \"shouldBreakMaskChain\": false,\n      \"style\": Object {\n        \"_class\": \"style\",\n        \"borderOptions\": Object {\n          \"_class\": \"borderOptions\",\n          \"dashPattern\": Array [],\n          \"isEnabled\": false,\n          \"lineCapStyle\": 0,\n          \"lineJoinStyle\": 0,\n        },\n        \"colorControls\": Object {\n          \"_class\": \"colorControls\",\n          \"brightness\": 1,\n          \"contrast\": 1,\n          \"hue\": 1,\n          \"isEnabled\": false,\n          \"saturation\": 1,\n        },\n        \"contextSettings\": Object {\n          \"_class\": \"graphicsContextSettings\",\n          \"blendMode\": 0,\n          \"opacity\": 1,\n        },\n        \"endMarkerType\": 0,\n        \"fills\": Array [],\n        \"innerShadows\": Array [],\n        \"miterLimit\": 10,\n        \"shadows\": Array [],\n        \"startMarkerType\": 0,\n        \"windingRule\": 1,\n      },\n    },\n  ],\n  \"name\": \"Svg\",\n  \"nameIsFixed\": false,\n  \"resizingConstraint\": 63,\n  \"resizingType\": 0,\n  \"rotation\": 0,\n  \"shouldBreakMaskChain\": false,\n  \"style\": Object {\n    \"_class\": \"style\",\n    \"borderOptions\": Object {\n      \"_class\": \"borderOptions\",\n      \"dashPattern\": Array [],\n      \"isEnabled\": false,\n      \"lineCapStyle\": 0,\n      \"lineJoinStyle\": 0,\n    },\n    \"colorControls\": Object {\n      \"_class\": \"colorControls\",\n      \"brightness\": 1,\n      \"contrast\": 1,\n      \"hue\": 1,\n      \"isEnabled\": false,\n      \"saturation\": 1,\n    },\n    \"contextSettings\": Object {\n      \"_class\": \"graphicsContextSettings\",\n      \"blendMode\": 0,\n      \"opacity\": 1,\n    },\n    \"endMarkerType\": 0,\n    \"fills\": Array [],\n    \"innerShadows\": Array [],\n    \"miterLimit\": 10,\n    \"shadows\": Array [],\n    \"startMarkerType\": 0,\n    \"windingRule\": 1,\n  },\n}\n`;\n"
  },
  {
    "path": "__tests__/jest/index.ts",
    "content": "import * as ReactSketch from '../../src';\n\ndescribe('public API', () => {\n  it('exports render', () => {\n    expect(ReactSketch.render).toBeDefined();\n  });\n  it('exports renderToJSON', () => {\n    expect(ReactSketch.renderToJSON).toBeDefined();\n  });\n  it('exports StyleSheet', () => {\n    expect(ReactSketch.StyleSheet).toBeDefined();\n  });\n  it('exports Document', () => {\n    expect(ReactSketch.Document).toBeDefined();\n  });\n  it('exports Page', () => {\n    expect(ReactSketch.Page).toBeDefined();\n  });\n  it('exports Artboard', () => {\n    expect(ReactSketch.Artboard).toBeDefined();\n  });\n  it('exports Image', () => {\n    expect(ReactSketch.Image).toBeDefined();\n  });\n  it('exports RedBox', () => {\n    expect(ReactSketch.RedBox).toBeDefined();\n  });\n  it('exports Text', () => {\n    expect(ReactSketch.Text).toBeDefined();\n  });\n  it('exports TextStyles', () => {\n    expect(ReactSketch.TextStyles).toBeDefined();\n  });\n  it('exports View', () => {\n    expect(ReactSketch.View).toBeDefined();\n  });\n  it('exports Platform', () => {\n    expect(ReactSketch.Platform).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "__tests__/jest/jsonUtils/computeTextTree.ts",
    "content": "import { computeTextTree } from '../../../src/jsonUtils/computeTextTree';\nimport { Context } from '../../../src/utils/Context';\n\n// Example Text component tree\nconst treeStub = {\n  type: 'text',\n  props: {\n    name: 'Swatch Hex',\n    style: {\n      color: '#636464',\n      zIndex: 1,\n    },\n  },\n  children: [\n    '#F3F4F4',\n    ' ',\n    {\n      type: 'text',\n      props: {\n        name: 'Text',\n        style: {\n          color: 'blue',\n        },\n      },\n      children: ['Hello World'],\n    },\n  ],\n};\n\n// Correct Output\nconst treeFixture = [\n  { content: '#F3F4F4', textStyles: {} },\n  { content: ' ', textStyles: {} },\n  { content: 'Hello World', textStyles: { color: 'blue' } },\n];\n\ndescribe('Compute Text Tree', () => {\n  it('correctly handle Text nodes', () => {\n    const tree = computeTextTree(treeStub, new Context());\n    expect(tree).toEqual(treeFixture);\n  });\n});\n"
  },
  {
    "path": "__tests__/jest/jsonUtils/computeYogaNode.ts",
    "content": "import yoga from 'yoga-layout-prebuilt';\nimport { computeYogaNode } from '../../../src/jsonUtils/computeYogaNode';\nimport { Context } from '../../../src/utils/Context';\nimport bridge from '../../../src/platformBridges/macos';\n\nconst widthAndHeightStylesStub = {\n  width: 10,\n  height: 10,\n};\n\nconst widthAndHeightStylesStubFixture = {\n  left: 0,\n  right: 0,\n  top: 0,\n  bottom: 0,\n  width: 10,\n  height: 10,\n};\n\nconst createTreeNode = (style: { [key: string]: number | string }) => ({\n  type: 'foo',\n  props: {\n    style,\n  },\n  children: [],\n});\n\nconst createYogaNodes = (\n  styles: Array<{ [key: string]: number | string }>,\n  containerWidth?: number,\n  containerHeight?: number,\n) => {\n  const yogaNodes = [];\n  styles.forEach((style) => {\n    const treeNode = createTreeNode(style);\n    const ctx = new Context();\n    const { node } = computeYogaNode(bridge)(treeNode, ctx);\n    node.calculateLayout(\n      containerWidth || undefined,\n      containerHeight || undefined,\n      yoga.DIRECTION_LTR,\n    );\n    yogaNodes.push(node.getComputedLayout());\n  });\n\n  return yogaNodes;\n};\n\ndescribe('Compute Yoga Node', () => {\n  it('correctly handles width: 0, auto, number', () => {\n    const stylesToTest = [{ width: 100 }, { width: 0 }, { width: 'auto' }];\n    const [numberNode, noneNode, autoNode] = createYogaNodes(stylesToTest);\n\n    expect(numberNode.width).toEqual(100);\n    expect(noneNode.width).toEqual(0);\n    expect(autoNode.width).toEqual(0);\n  });\n\n  it('correctly handles height: 0, auto, number', () => {\n    const stylesToTest = [{ height: 100 }, { height: 0 }, { height: 'auto' }];\n    const [numberNode, noneNode, autoNode] = createYogaNodes(stylesToTest);\n\n    expect(numberNode.height).toEqual(100);\n    expect(noneNode.height).toEqual(0);\n    expect(autoNode.height).toEqual(0);\n  });\n\n  it('correctly handles min-height: 0 & number', () => {\n    const stylesToTest = [{ minHeight: 100 }, { minHeight: 0 }];\n    const [numberNode, noneNode] = createYogaNodes(stylesToTest);\n\n    expect(numberNode.height).toEqual(100);\n    expect(noneNode.height).toEqual(0);\n  });\n\n  it('correctly handles max-height: 0 & number', () => {\n    const stylesToTest = [{ height: '100%', maxHeight: 100 }, { maxHeight: 0 }];\n    const [numberNode, noneNode] = createYogaNodes(stylesToTest, 500, 500);\n\n    expect(numberNode.height).toEqual(100);\n    expect(noneNode.height).toEqual(0);\n  });\n\n  it('correctly handles min-width: 0 & number', () => {\n    const stylesToTest = [{ minWidth: 100 }, { minWidth: 0 }];\n    const [numberNode, noneNode] = createYogaNodes(stylesToTest);\n\n    expect(numberNode.width).toEqual(100);\n    expect(noneNode.width).toEqual(0);\n  });\n\n  it('correctly handles max-width: 0 & number', () => {\n    const stylesToTest = [{ width: '100%', maxWidth: 100 }, { maxWidth: 0 }];\n    const [numberNode, noneNode] = createYogaNodes(stylesToTest, 500, 500);\n\n    expect(numberNode.width).toEqual(100);\n    expect(noneNode.width).toEqual(0);\n  });\n\n  it('correctly handles margin', () => {\n    const stylesToTest = [{ margin: 100 }, { margin: 0 }, { margin: 'auto' }];\n    const [numberNode, noneNode, autoNode] = createYogaNodes(stylesToTest);\n\n    expect(numberNode).toEqual({\n      left: 100,\n      right: 100,\n      top: 100,\n      bottom: 100,\n      width: 0,\n      height: 0,\n    });\n    expect(noneNode).toEqual({\n      left: 0,\n      right: 0,\n      top: 0,\n      bottom: 0,\n      width: 0,\n      height: 0,\n    });\n    expect(autoNode).toEqual({\n      left: 0,\n      right: 0,\n      top: 0,\n      bottom: 0,\n      width: 0,\n      height: 0,\n    });\n  });\n\n  it('correctly handles padding', () => {\n    const stylesToTest = [{ padding: 100 }, { padding: 0 }];\n    const [numberNode, noneNode] = createYogaNodes(stylesToTest);\n\n    expect(numberNode).toEqual({\n      left: 0,\n      right: 0,\n      top: 0,\n      bottom: 0,\n      width: 200,\n      height: 200,\n    });\n    expect(noneNode).toEqual({\n      left: 0,\n      right: 0,\n      top: 0,\n      bottom: 0,\n      width: 0,\n      height: 0,\n    });\n  });\n\n  it('correctly handles border', () => {\n    const stylesToTest = [{ borderWidth: 10 }, { borderWidth: 0 }];\n    const [numberNode, noneNode] = createYogaNodes(stylesToTest);\n\n    expect(numberNode).toEqual({\n      left: 0,\n      right: 0,\n      top: 0,\n      bottom: 0,\n      width: 20,\n      height: 20,\n    });\n    expect(noneNode).toEqual({\n      left: 0,\n      right: 0,\n      top: 0,\n      bottom: 0,\n      width: 0,\n      height: 0,\n    });\n  });\n\n  it('correctly handles flex: 0, number', () => {\n    const stylesToTest = [{ flex: 1 }, { flex: 0 }];\n    const [numberNode, noneNode] = createYogaNodes(stylesToTest);\n\n    expect(numberNode.width).toEqual(0);\n    expect(noneNode.width).toEqual(0);\n  });\n\n  it('correctly handles flexGrow: 0, number', () => {\n    const stylesToTest = [{ flexGrow: 1 }, { flexGrow: 0 }];\n    const [numberNode, noneNode] = createYogaNodes(stylesToTest);\n\n    expect(numberNode.width).toEqual(0);\n    expect(noneNode.width).toEqual(0);\n  });\n\n  it('correctly handles flexShrink: 0, number', () => {\n    const stylesToTest = [{ flexShrink: 1 }, { flexShrink: 0 }];\n    const [numberNode, noneNode] = createYogaNodes(stylesToTest);\n\n    expect(numberNode.width).toEqual(0);\n    expect(noneNode.width).toEqual(0);\n  });\n\n  it('correctly handles flexBasis: 0, number', () => {\n    const stylesToTest = [{ flexBasis: 1 }, { flexBasis: 0 }];\n    const [numberNode, noneNode] = createYogaNodes(stylesToTest);\n\n    expect(numberNode.width).toEqual(0);\n    expect(noneNode.width).toEqual(0);\n  });\n\n  it('correctly handles position: relative & absolute', () => {\n    const stylesToTest = [\n      { position: 'relative', left: 10 },\n      { position: 'absolute', top: 10 },\n    ];\n    const [relativeNode, absoluteNode] = createYogaNodes(stylesToTest);\n\n    expect(relativeNode).toEqual({\n      left: 10,\n      right: 10,\n      top: 0,\n      bottom: 0,\n      width: 0,\n      height: 0,\n    });\n    expect(absoluteNode).toEqual({\n      left: 0,\n      right: 0,\n      top: 10,\n      bottom: 10,\n      width: 0,\n      height: 0,\n    });\n  });\n\n  it('correctly handles display: flex & none', () => {\n    const stylesToTest = [\n      { display: 'flex', ...widthAndHeightStylesStub },\n      { display: 'none', width: 10, height: 10 },\n    ];\n    const [relativeNode, absoluteNode] = createYogaNodes(stylesToTest);\n\n    expect(relativeNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(absoluteNode).toEqual(widthAndHeightStylesStubFixture);\n  });\n\n  it('correctly handles overflow: visible, scroll, hidden', () => {\n    const stylesToTest = [\n      { overflow: 'visible', ...widthAndHeightStylesStub },\n      { overflow: 'scroll', ...widthAndHeightStylesStub },\n      { overflow: 'hidden', ...widthAndHeightStylesStub },\n    ];\n    const [visibleNode, scrollNode, hiddenNode] = createYogaNodes(stylesToTest);\n\n    expect(visibleNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(scrollNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(hiddenNode).toEqual(widthAndHeightStylesStubFixture);\n  });\n\n  it('correctly handles flexDirection', () => {\n    const stylesToTest = [\n      { flexDirection: 'row', ...widthAndHeightStylesStub },\n      { flexDirection: 'column', ...widthAndHeightStylesStub },\n      { flexDirection: 'row-reverse', ...widthAndHeightStylesStub },\n      { flexDirection: 'column-reverse', ...widthAndHeightStylesStub },\n    ];\n    const [rowNode, colNode, rowReverseNode, colReverseNode] = createYogaNodes(stylesToTest);\n\n    expect(rowNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(colNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(rowReverseNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(colReverseNode).toEqual(widthAndHeightStylesStubFixture);\n  });\n\n  it('correctly handles justifyContent', () => {\n    const stylesToTest = [\n      { justifyContent: 'flex-start', ...widthAndHeightStylesStub },\n      { justifyContent: 'flex-end', ...widthAndHeightStylesStub },\n      { justifyContent: 'center', ...widthAndHeightStylesStub },\n      { justifyContent: 'space-between', ...widthAndHeightStylesStub },\n      { justifyContent: 'space-around', ...widthAndHeightStylesStub },\n    ];\n    const [startNode, endNode, centerNode, spaceBetweenNode, spaceAroundNode] = createYogaNodes(\n      stylesToTest,\n    );\n\n    expect(startNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(endNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(centerNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(spaceBetweenNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(spaceAroundNode).toEqual(widthAndHeightStylesStubFixture);\n  });\n\n  it('correctly handles alignContent', () => {\n    const stylesToTest = [\n      { alignContent: 'flex-start', ...widthAndHeightStylesStub },\n      { alignContent: 'flex-end', ...widthAndHeightStylesStub },\n      { alignContent: 'center', ...widthAndHeightStylesStub },\n      { alignContent: 'stretch', ...widthAndHeightStylesStub },\n      { alignContent: 'baseline', ...widthAndHeightStylesStub },\n      { alignContent: 'space-between', ...widthAndHeightStylesStub },\n      { alignContent: 'space-around', ...widthAndHeightStylesStub },\n      { alignContent: 'auto', ...widthAndHeightStylesStub },\n    ];\n    const [\n      startNode,\n      endNode,\n      centerNode,\n      stretchNode,\n      baselineNode,\n      spaceBetweenNode,\n      spaceAroundNode,\n      autoNode,\n    ] = createYogaNodes(stylesToTest);\n\n    expect(startNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(endNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(centerNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(stretchNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(baselineNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(spaceBetweenNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(spaceAroundNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(autoNode).toEqual(widthAndHeightStylesStubFixture);\n  });\n\n  it('correctly handles alignItems', () => {\n    const stylesToTest = [\n      { alignItems: 'flex-start', ...widthAndHeightStylesStub },\n      { alignItems: 'flex-end', ...widthAndHeightStylesStub },\n      { alignItems: 'center', ...widthAndHeightStylesStub },\n      { alignItems: 'stretch', ...widthAndHeightStylesStub },\n      { alignItems: 'baseline', ...widthAndHeightStylesStub },\n    ];\n    const [startNode, endNode, centerNode, stretchNode, baselineNode] = createYogaNodes(\n      stylesToTest,\n    );\n\n    expect(startNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(endNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(centerNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(stretchNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(baselineNode).toEqual(widthAndHeightStylesStubFixture);\n  });\n\n  it('correctly handles alignSelf', () => {\n    const stylesToTest = [\n      { alignSelf: 'flex-start', ...widthAndHeightStylesStub },\n      { alignSelf: 'flex-end', ...widthAndHeightStylesStub },\n      { alignSelf: 'center', ...widthAndHeightStylesStub },\n      { alignSelf: 'stretch', ...widthAndHeightStylesStub },\n      { alignSelf: 'baseline', ...widthAndHeightStylesStub },\n    ];\n    const [startNode, endNode, centerNode, stretchNode, baselineNode] = createYogaNodes(\n      stylesToTest,\n    );\n\n    expect(startNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(endNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(centerNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(stretchNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(baselineNode).toEqual(widthAndHeightStylesStubFixture);\n  });\n\n  it('correctly handles flexWrap', () => {\n    const stylesToTest = [\n      { flexWrap: 'no-wrap', ...widthAndHeightStylesStub },\n      { flexWrap: 'wrap', ...widthAndHeightStylesStub },\n      { flexWrap: 'wrap-reverse', ...widthAndHeightStylesStub },\n    ];\n    const [noWrapNode, wrapNode, wrapReverseNode] = createYogaNodes(stylesToTest);\n\n    expect(noWrapNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(wrapNode).toEqual(widthAndHeightStylesStubFixture);\n    expect(wrapReverseNode).toEqual(widthAndHeightStylesStubFixture);\n  });\n});\n"
  },
  {
    "path": "__tests__/jest/jsonUtils/computeYogaTree.ts",
    "content": "import yoga from 'yoga-layout-prebuilt';\nimport { computeYogaTree } from '../../../src/jsonUtils/computeYogaTree';\nimport { Context } from '../../../src/utils/Context';\nimport bridge from '../../../src/platformBridges/macos';\n\nconst treeRootStub = {\n  type: 'artboard',\n  props: {\n    style: {\n      flexDirection: 'row',\n      flexWrap: 'wrap',\n      width: 416,\n    },\n    name: 'Swatches',\n  },\n  children: [\n    {\n      type: 'view',\n      props: {\n        name: 'Swatch Haus',\n        style: {\n          backgroundColor: '#F3F4F4',\n          height: 96,\n          marginTop: 4,\n          marginRight: 4,\n          marginBottom: 4,\n          marginLeft: 4,\n          paddingTop: 8,\n          paddingRight: 8,\n          paddingBottom: 8,\n          paddingLeft: 8,\n          width: 96,\n        },\n      },\n      children: [],\n    },\n  ],\n};\n\ncomputeYogaTree(bridge)(treeRootStub, new Context());\n\ndescribe('Compute Yoga Tree', () => {\n  it('correctly create yoga nodes into layout tree', () => {\n    const yogaTree = computeYogaTree(bridge)(treeRootStub, new Context());\n    yogaTree.calculateLayout(undefined, undefined, yoga.DIRECTION_LTR);\n    expect(yogaTree.getComputedLayout()).toEqual({\n      bottom: 0,\n      height: 104,\n      left: 0,\n      right: 0,\n      top: 0,\n      width: 416,\n    });\n\n    expect(yogaTree.getChild(0).getComputedLayout()).toEqual({\n      bottom: 4,\n      height: 96,\n      left: 4,\n      right: 4,\n      top: 4,\n      width: 96,\n    });\n  });\n});\n"
  },
  {
    "path": "__tests__/jest/jsonUtils/layerGroup.ts",
    "content": "import { layerGroup } from '../../../src/jsonUtils/layerGroup';\n\ndescribe('layer group', () => {\n  it('is correctly constructed', () => {\n    const group = layerGroup(100, 200, 300, 400, 0.5);\n\n    expect(group).toHaveProperty('frame.x', 100);\n    expect(group).toHaveProperty('frame.y', 200);\n    expect(group).toHaveProperty('frame.width', 300);\n    expect(group).toHaveProperty('frame.height', 400);\n    expect(group).toHaveProperty('style.contextSettings.opacity', 0.5);\n  });\n});\n"
  },
  {
    "path": "__tests__/jest/jsonUtils/models.ts",
    "content": "import {\n  generateID,\n  makeColorFromCSS,\n  makeColorFill,\n  makeRect,\n  makeSymbolInstance,\n  makeSymbolMaster,\n} from '../../../src/jsonUtils/models';\n\ndescribe('generateID', () => {\n  it('is unique', () => {\n    expect(generateID()).not.toBe(generateID());\n  });\n  it('seed generates different ID', () => {\n    expect(generateID('test')).not.toBe(generateID('test'));\n  });\n  it('hardcoded seed generates same ID', () => {\n    expect(generateID('test', true)).toBe(generateID('test', true));\n  });\n});\n\nconst BLACK = {\n  _class: 'color',\n  red: 0,\n  green: 0,\n  blue: 0,\n  alpha: 1,\n};\nconst WHITE = {\n  _class: 'color',\n  red: 1,\n  green: 1,\n  blue: 1,\n  alpha: 1,\n};\nconst GOLD = {\n  _class: 'color',\n  red: 0.8745098039215686,\n  green: 0.7294117647058823,\n  blue: 0.4117647058823529,\n  alpha: 1,\n};\nconst PURPLE = {\n  _class: 'color',\n  red: 0.4,\n  green: 0.2,\n  blue: 0.6,\n  alpha: 1,\n};\n\ndescribe('makeColorFromCSS', () => {\n  it('works with hex colors', () => {\n    expect(makeColorFromCSS('#000')).toEqual(BLACK);\n    expect(makeColorFromCSS('#000000')).toEqual(BLACK);\n    expect(makeColorFromCSS('#FFF')).toEqual(WHITE);\n    expect(makeColorFromCSS('#FFFFFF')).toEqual(WHITE);\n    expect(makeColorFromCSS('#DFBA69')).toEqual(GOLD);\n  });\n\n  it('works with named colors', () => {\n    expect(makeColorFromCSS('black')).toEqual(BLACK);\n    expect(makeColorFromCSS('white')).toEqual(WHITE);\n    expect(makeColorFromCSS('rebeccapurple')).toEqual(PURPLE);\n  });\n\n  it('is case-insensitive', () => {\n    expect(makeColorFromCSS('BLACK')).toEqual(BLACK);\n    expect(makeColorFromCSS('wHIte')).toEqual(WHITE);\n    expect(makeColorFromCSS('rebeccaPurple')).toEqual(PURPLE);\n  });\n\n  it('works with rgb colors', () => {\n    expect(makeColorFromCSS('rgb(0, 0, 0)')).toEqual(BLACK);\n    expect(makeColorFromCSS('rgb(255, 255, 255)')).toEqual(WHITE);\n    expect(makeColorFromCSS('rgb(102, 51, 153)')).toEqual(PURPLE);\n  });\n\n  it('works with rgba colors', () => {\n    expect(makeColorFromCSS('rgba(0, 0, 0, 1)')).toEqual(BLACK);\n    expect(makeColorFromCSS('rgba(255, 255, 255, 1)')).toEqual(WHITE);\n    expect(makeColorFromCSS('rgba(102, 51, 153, 1)')).toEqual(PURPLE);\n  });\n\n  it('multiplies rgba components with an alpha', () => {\n    expect(makeColorFromCSS('rgba(0, 0, 0, 0.5)').alpha).toBeCloseTo(0.5);\n    expect(makeColorFromCSS('rgba(0, 0, 0, 1)', 0.5).alpha).toBeCloseTo(0.5);\n    expect(makeColorFromCSS('rgba(0, 0, 0, 0.5)', 0.5).alpha).toBeCloseTo(0.25);\n  });\n\n  it('works with hsl colors', () => {\n    expect(makeColorFromCSS('hsl(0, 0%, 0%)')).toEqual(BLACK);\n    expect(makeColorFromCSS('hsl(0, 0%, 100%)')).toEqual(WHITE);\n  });\n\n  it('works with hsla colors', () => {\n    expect(makeColorFromCSS('hsla(0, 0%, 0%, 1)')).toEqual(BLACK);\n    expect(makeColorFromCSS('hsla(0, 0%, 100%, 1)')).toEqual(WHITE);\n  });\n});\n\ndescribe('makeColorFill', () => {\n  it('sets the correct color', () => {\n    expect(makeColorFill('#000')).toHaveProperty('color', BLACK);\n    expect(makeColorFill('#fff')).toHaveProperty('color', WHITE);\n    expect(makeColorFill('rebeccapurple')).toHaveProperty('color', PURPLE);\n    expect(makeColorFill('#DFBA69')).toHaveProperty('color', GOLD);\n  });\n});\n\ndescribe('makeRect', () => {\n  it('is correctly constructed', () => {\n    const group = makeRect(100, 200, 300, 400);\n\n    expect(group).toHaveProperty('x', 100);\n    expect(group).toHaveProperty('y', 200);\n    expect(group).toHaveProperty('width', 300);\n    expect(group).toHaveProperty('height', 400);\n  });\n});\n\ndescribe('makeSymbolInstance', () => {\n  it('is correctly constructed', () => {\n    const instance = makeSymbolInstance(\n      makeRect(0, 0, 100, 100),\n      'this is the symbol id',\n      'this is the name',\n    );\n\n    expect(instance).toHaveProperty('symbolID', 'this is the symbol id');\n    expect(instance).toHaveProperty('name', 'this is the name');\n  });\n});\n\ndescribe('makeSymbolMaster', () => {\n  it('is correctly constructed', () => {\n    const master = makeSymbolMaster(\n      makeRect(0, 0, 100, 100),\n      'this is the symbol id',\n      'this is the name',\n    );\n\n    expect(master).toHaveProperty('symbolID', 'this is the symbol id');\n    expect(master).toHaveProperty('name', 'this is the name');\n  });\n});\n"
  },
  {
    "path": "__tests__/jest/jsonUtils/shapeLayers.ts",
    "content": "import {\n  makeRectPath,\n  makeShapePath,\n  makeRectShapeLayer,\n  makeShapeGroup,\n} from '../../../src/jsonUtils/shapeLayers';\n\ndescribe('makeRectPath', () => {\n  it('is correctly constructed', () => {\n    const path = makeRectPath([10, 20, 30, 40]);\n\n    expect(path.points[0]).toHaveProperty('cornerRadius', 10);\n    expect(path.points[1]).toHaveProperty('cornerRadius', 20);\n    expect(path.points[2]).toHaveProperty('cornerRadius', 30);\n    expect(path.points[3]).toHaveProperty('cornerRadius', 40);\n  });\n});\n\ndescribe('makeShapePath', () => {\n  it('is correctly constructed', () => {\n    const frame = { foo: 'bar' };\n    const path = { baz: 'qux' };\n    // @ts-ignore\n    const shapePath = makeShapePath(frame, path);\n\n    expect(shapePath).toHaveProperty('frame', frame);\n    expect(shapePath).toHaveProperty('baz', 'qux');\n  });\n});\n\ndescribe('makeRectShapeLayer', () => {\n  it('is correctly constructed', () => {\n    const shapeLayer = makeRectShapeLayer(100, 200, 300, 400, [10, 20, 30, 40]);\n\n    expect(shapeLayer).toHaveProperty('frame.x', 100);\n    expect(shapeLayer).toHaveProperty('frame.y', 200);\n    expect(shapeLayer).toHaveProperty('frame.width', 300);\n    expect(shapeLayer).toHaveProperty('frame.height', 400);\n    expect(shapeLayer).toHaveProperty('fixedRadius', 10);\n  });\n});\n\ndescribe('makeShapeGroup', () => {\n  it('is correctly constructed', () => {\n    const frame = { foo: 'bar' };\n    const layers = [{ baz: 'qux' }];\n    const fills = ['foo', 'bar'];\n\n    // @ts-ignore\n    const shapeGroup = makeShapeGroup(frame, layers, undefined, undefined, fills);\n\n    expect(shapeGroup).toHaveProperty('frame', frame);\n    expect(shapeGroup).toHaveProperty('layers', layers);\n    expect(shapeGroup).toHaveProperty('style.fills', fills);\n  });\n});\n"
  },
  {
    "path": "__tests__/jest/jsonUtils/style.ts",
    "content": "import { makeBorderOptions, makeShadow } from '../../../src/jsonUtils/style';\n\ndescribe('makeBorderOptions', () => {\n  it('makes solid borders', () => {\n    expect(makeBorderOptions('solid', 1)).toHaveProperty('dashPattern', []);\n  });\n\n  it('makes dotted borders', () => {\n    expect(makeBorderOptions('dotted', 1)).toHaveProperty('dashPattern', [1, 1]);\n\n    expect(makeBorderOptions('dotted', 5)).toHaveProperty('dashPattern', [5, 5]);\n  });\n\n  it('makes dashed borders', () => {\n    expect(makeBorderOptions('dashed', 1)).toHaveProperty('dashPattern', [3, 3]);\n\n    expect(makeBorderOptions('dashed', 5)).toHaveProperty('dashPattern', [15, 15]);\n  });\n});\n\ndescribe('makeShadow', () => {\n  it('has sensible defaults', () => {\n    const result = makeShadow({});\n\n    expect(result).toHaveProperty('color.alpha', 1);\n    expect(result).toHaveProperty('blurRadius', 1);\n    expect(result).toHaveProperty('offsetX', 0);\n    expect(result).toHaveProperty('offsetY', 0);\n  });\n\n  it('passes through props', () => {\n    const result = makeShadow({\n      shadowOpacity: 0.5,\n      shadowColor: 'red',\n      shadowRadius: 10,\n      shadowOffset: {\n        width: 5,\n        height: 7,\n      },\n    });\n\n    expect(result).toHaveProperty('color.alpha', 0.5);\n    expect(result).toHaveProperty('blurRadius', 10);\n    expect(result).toHaveProperty('offsetX', 5);\n    expect(result).toHaveProperty('offsetY', 7);\n  });\n\n  it('combines rgba alpha & shadowOpacity', () => {\n    const result = makeShadow({\n      shadowOpacity: 0.5,\n      shadowColor: 'rgba(0,0,0,0.5)',\n      shadowRadius: 10,\n      shadowOffset: {\n        width: 5,\n        height: 7,\n      },\n    });\n\n    expect(result.color.alpha).toBeCloseTo(0.25);\n  });\n});\n"
  },
  {
    "path": "__tests__/jest/reactTreeToFlexTree.ts",
    "content": "import yoga from 'yoga-layout-prebuilt';\nimport { computeYogaTree } from '../../src/jsonUtils/computeYogaTree';\nimport { Context } from '../../src/utils/Context';\nimport { reactTreeToFlexTree } from '../../src/buildTree';\nimport bridge from '../../src/platformBridges/macos';\n\nconst treeRootStub = {\n  type: 'artboard',\n  props: {\n    style: {\n      flexDirection: 'row',\n      flexWrap: 'wrap',\n      width: 416,\n    },\n    name: 'Swatches',\n  },\n  children: [\n    {\n      type: 'view',\n      props: {\n        name: 'Layer 1',\n        style: {\n          height: 100,\n          position: 'absolute',\n          width: 100,\n          zIndex: 1,\n        },\n      },\n      children: [],\n    },\n    {\n      type: 'view',\n      props: {\n        name: 'Layer 3',\n        style: {\n          height: 300,\n          position: 'absolute',\n          width: 300,\n          zIndex: 3,\n        },\n      },\n      children: [],\n    },\n    {\n      type: 'view',\n      props: {\n        name: 'Layer 2',\n        style: {\n          height: 200,\n          position: 'absolute',\n          width: 200,\n          zIndex: 2,\n        },\n      },\n      children: [],\n    },\n  ],\n};\n\ndescribe('Compute Flex Tree', () => {\n  it('correctly creates flex tree', () => {\n    const yogaNode = computeYogaTree(bridge)(treeRootStub, new Context());\n    yogaNode.calculateLayout(undefined, undefined, yoga.DIRECTION_LTR);\n    const tree = reactTreeToFlexTree(treeRootStub, yogaNode, new Context());\n\n    expect(tree.children).toEqual([\n      {\n        type: 'view',\n        style: {\n          height: 100,\n          position: 'absolute',\n          width: 100,\n          zIndex: 1,\n        },\n        textStyle: {},\n        layout: {\n          left: 0,\n          right: 0,\n          top: 0,\n          bottom: 0,\n          width: 100,\n          height: 100,\n        },\n        props: {\n          name: 'Layer 1',\n          style: {\n            height: 100,\n            position: 'absolute',\n            width: 100,\n            zIndex: 1,\n          },\n          textNodes: [],\n        },\n        children: [],\n      },\n      {\n        type: 'view',\n        style: {\n          height: 200,\n          position: 'absolute',\n          width: 200,\n          zIndex: 2,\n        },\n        textStyle: {},\n        layout: {\n          left: 0,\n          right: 0,\n          top: 0,\n          bottom: 0,\n          width: 200,\n          height: 200,\n        },\n        props: {\n          name: 'Layer 2',\n          style: {\n            height: 200,\n            position: 'absolute',\n            width: 200,\n            zIndex: 2,\n          },\n          textNodes: [],\n        },\n        children: [],\n      },\n      {\n        type: 'view',\n        style: {\n          height: 300,\n          position: 'absolute',\n          width: 300,\n          zIndex: 3,\n        },\n        textStyle: {},\n        layout: {\n          left: 0,\n          right: 0,\n          top: 0,\n          bottom: 0,\n          width: 300,\n          height: 300,\n        },\n        props: {\n          name: 'Layer 3',\n          style: {\n            height: 300,\n            position: 'absolute',\n            width: 300,\n            zIndex: 3,\n          },\n          textNodes: [],\n        },\n        children: [],\n      },\n    ]);\n  });\n});\n"
  },
  {
    "path": "__tests__/jest/sharedStyles/TextStyles.ts",
    "content": "import bridge from '../../../src/platformBridges/macos';\n\nlet TextStyles;\nlet doc;\nlet sharedTextStyles;\n\nbeforeEach(() => {\n  jest.resetModules();\n\n  jest.mock('../../../src/utils/getSketchVersion', () => ({\n    getSketchVersion: jest.fn(() => 51),\n  }));\n\n  TextStyles = require('../../../src/sharedStyles/TextStyles').TextStyles;\n\n  sharedTextStyles = require('../../../src/utils/sharedTextStyles');\n\n  jest.mock('../../../src/utils/sharedTextStyles');\n\n  TextStyles = TextStyles(() => bridge);\n  sharedTextStyles = sharedTextStyles.sharedTextStyles;\n\n  sharedTextStyles.setDocument = jest.fn((doc) => {\n    if (!doc) {\n      throw new Error('Please provide a sketch document reference');\n    }\n  });\n  sharedTextStyles.addStyle = jest.fn(() => 'styleId');\n  sharedTextStyles.setStyles = jest.fn(() => sharedTextStyles);\n\n  doc = jest.fn();\n});\n\ndescribe('create', () => {\n  describe('without a context', () => {\n    it('it errors', () => {\n      const styles = {};\n\n      expect(() => TextStyles.create({}, styles)).toThrowError(\n        /Please provide a sketch document reference/,\n      );\n    });\n  });\n\n  describe('with a context', () => {\n    it('clears clearExistingStyles when true', () => {\n      TextStyles.create(\n        {},\n        {\n          clearExistingStyles: true,\n          document: doc,\n        },\n      );\n\n      expect(sharedTextStyles.setStyles).toHaveBeenCalled();\n    });\n\n    it('doesn’t clearExistingStyles when false', () => {\n      TextStyles.create(\n        {},\n        {\n          clearExistingStyles: false,\n          document: doc,\n        },\n      );\n      expect(sharedTextStyles.setStyles).not.toHaveBeenCalled();\n    });\n\n    it('stores one style', () => {\n      const styles = {\n        foo: {\n          fontSize: 'bar',\n        },\n      };\n\n      const res = TextStyles.create(styles, { document: doc });\n\n      expect(Object.keys(res).length).toBe(1);\n    });\n\n    it('stores unique styles seperately', () => {\n      const styles = {\n        foo: {\n          fontSize: 'bar',\n        },\n        bar: {\n          fontSize: 'baz',\n        },\n      };\n\n      const res = TextStyles.create(styles, { document: doc });\n\n      expect(Object.keys(res).length).toBe(2);\n      expect(sharedTextStyles.addStyle).toHaveBeenCalledTimes(2);\n    });\n\n    it('merges duplicate styles', () => {\n      const styles = {\n        foo: {\n          fontSize: 'foo',\n        },\n        bar: {\n          fontSize: 'foo',\n        },\n      };\n\n      const res = TextStyles.create(styles, { document: doc });\n\n      expect(Object.keys(res).length).toBe(1);\n      expect(sharedTextStyles.addStyle).toHaveBeenCalledTimes(2);\n    });\n\n    it('only stores text attributes', () => {\n      const whitelist = [\n        'color',\n        'fontFamily',\n        'fontSize',\n        'fontStyle',\n        'fontWeight',\n        'textShadowOffset',\n        'textShadowRadius',\n        'textShadowColor',\n        'textTransform',\n        'letterSpacing',\n        'lineHeight',\n        'textAlign',\n        'writingDirection',\n      ];\n\n      const blacklist = ['foo', 'bar', 'baz'];\n\n      const input = [...whitelist, ...blacklist].reduce(\n        (acc, key) => ({\n          ...acc,\n          [key]: '',\n        }),\n        {},\n      );\n\n      const res = TextStyles.create({ foo: input }, { document: doc });\n\n      const firstStoredStyle = res[Object.keys(res)[0]].cssStyle;\n\n      whitelist.forEach((key) => {\n        expect(firstStoredStyle).toHaveProperty(key, '');\n      });\n\n      blacklist.forEach((key) => {\n        expect(firstStoredStyle).not.toHaveProperty(key);\n      });\n    });\n  });\n});\n\ndescribe('resolve', () => {\n  beforeEach(() => {\n    TextStyles.create({}, { document: doc });\n  });\n\n  it('retrieves a matching style', () => {\n    const key = 'foo';\n    const styles = {\n      [key]: { fontSize: 'bar' },\n    };\n\n    TextStyles.create(styles, { document: doc });\n\n    expect(TextStyles.resolve(styles[key])).toBeDefined();\n    expect(sharedTextStyles.addStyle).toHaveBeenCalledTimes(1);\n  });\n\n  it('returns null with no matching style', () => {\n    const key = 'foo';\n    const styles = {\n      [key]: {\n        fontSize: 'bar',\n      },\n    };\n    const style2 = {\n      fontSize: 'qux',\n    };\n\n    TextStyles.create(styles, { document: doc });\n\n    expect(TextStyles.resolve(style2)).not.toBeDefined();\n    expect(sharedTextStyles.addStyle).toHaveBeenCalledTimes(1);\n  });\n});\n\ndescribe('get', () => {\n  it('finds a matching registered style by name', () => {\n    const styles = {\n      foo: {\n        fontSize: 'bar',\n      },\n      bar: {\n        fontSize: 'baz',\n      },\n    };\n\n    TextStyles.create(styles, { document: doc });\n\n    expect(TextStyles.get('foo')).toEqual(styles.foo);\n    expect(TextStyles.get('baz')).toEqual(undefined);\n  });\n\n  it('returns undefined when not found', () => {\n    const styles = {\n      foo: {\n        fontSize: 'bar',\n      },\n    };\n\n    TextStyles.create(styles, { document: doc });\n\n    expect(TextStyles.get('baz')).toEqual(undefined);\n  });\n});\n\ndescribe('clear', () => {\n  it('clears previously registered styles', () => {\n    const styles = {\n      foo: {\n        fontSize: 'bar',\n      },\n      bar: {\n        fontSize: 'baz',\n      },\n    };\n\n    TextStyles.create(styles, { document: doc });\n    TextStyles.clear();\n\n    expect(TextStyles.styles()).toEqual({});\n  });\n});\n"
  },
  {
    "path": "__tests__/jest/utils/isDefined.ts",
    "content": "import { isDefined } from '../../../src/utils/isDefined';\n\ndescribe('isNullOrUndefined', () => {\n  it('correctly identify null', () => {\n    const shouldBeNull = isDefined(null);\n\n    expect(shouldBeNull).toEqual(false);\n  });\n\n  it('correctly identify undefined', () => {\n    const shouldBeUndefined = isDefined(undefined);\n\n    expect(shouldBeUndefined).toEqual(false);\n  });\n\n  it('correctly identify zero (0)', () => {\n    const shouldBeZero = isDefined(0);\n\n    expect(shouldBeZero).toEqual(true);\n  });\n});\n"
  },
  {
    "path": "__tests__/jest/utils/sortObjectKeys.ts",
    "content": "import { sortObjectKeys } from '../../../src/utils/sortObjectKeys';\n\ntest('simple example', () => {\n  const a = {\n    foo: true,\n    bar: true,\n    qux: true,\n    baz: true,\n  };\n\n  const b = {\n    bar: true,\n    baz: true,\n    foo: true,\n    qux: true,\n  };\n\n  expect(sortObjectKeys(a)).toEqual(b);\n});\n"
  },
  {
    "path": "__tests__/jest/utils/zIndex.ts",
    "content": "import { zIndex } from '../../../src/utils/zIndex';\n\nconst noZIndexNode = {\n  props: {\n    style: {\n      zIndex: 0,\n    },\n  },\n};\n\nconst zIndexNode = {\n  props: {\n    style: {\n      zIndex: 1,\n    },\n  },\n};\n\nconst fixureThatShouldBeSortedDifferently = [noZIndexNode, zIndexNode];\nconst fixureThatShouldNotBeSortedDifferently = [noZIndexNode, noZIndexNode];\n\ndescribe('zIndex', () => {\n  it('correctly resort zIndex', () => {\n    // @ts-ignore\n    const shouldBeResorted = zIndex(fixureThatShouldBeSortedDifferently);\n    // @ts-ignore\n    expect(shouldBeResorted[0].props.style.zIndex).toEqual(0);\n  });\n\n  it('correctly add original index to returned objects ', () => {\n    // @ts-ignore\n    const shouldBeResorted = zIndex(fixureThatShouldBeSortedDifferently);\n\n    // @ts-ignore\n    expect(shouldBeResorted[0].oIndex).toEqual(0);\n  });\n\n  it('correctly resort zIndexes that are all the same', () => {\n    // @ts-ignore\n    const shouldNotBeResorted = zIndex(fixureThatShouldNotBeSortedDifferently);\n\n    // @ts-ignore\n    expect(shouldNotBeResorted[0].props.style.zIndex).toEqual(0);\n  });\n});\n"
  },
  {
    "path": "__tests__/skpm/basic.test.js",
    "content": "import * as React from 'react';\nimport * as sketch from 'sketch';\nimport { render, View, Artboard, Text } from '../../lib';\n\n// depending on where those tests run, we don't get the things,\n// eg. the context might be empty or there is no selected document\n// This make sure we always get something\nfunction getDoc(context, document) {\n  return context.document || (sketch.getSelectedDocument() || document).sketchObject;\n}\n\nconst colorList = {\n  Haus: '#F3F4F4',\n  Night: '#333',\n  Sur: '#96DBE4',\n  'Sur Dark': '#24828F',\n  Peach: '#EFADA0',\n  'Peach Dark': '#E37059',\n  Pear: '#93DAAB',\n  'Pear Dark': '#2E854B',\n};\n\ntest('should render a Page with a rectangle', (context, document) => {\n  const nativePage = getDoc(context, document).currentPage();\n  const Swatch = ({ name, hex }) => (\n    <View\n      name={`Swatch ${name}`}\n      style={{\n        height: 96,\n        width: 96,\n        margin: 4,\n        backgroundColor: hex,\n        padding: 8,\n      }}\n    >\n      <Text name=\"Swatch Name\" style={{ color: '#000', fontWeight: 'bold' }}>\n        {name}\n      </Text>\n      <Text name=\"Swatch Hex\" style={{ color: '#000' }}>\n        {hex}\n      </Text>\n    </View>\n  );\n\n  render(\n    <Artboard\n      name=\"Swatches\"\n      style={{\n        flexDirection: 'row',\n        flexWrap: 'wrap',\n        width: (96 + 8) * 4,\n      }}\n    >\n      {Object.keys(colorList).map(color => (\n        <Swatch name={color} hex={colorList[color]} key={color} />\n      ))}\n    </Artboard>,\n    nativePage,\n  );\n\n  const page = sketch.Page.fromNative(nativePage);\n  expect(page.layers[0].name).toBe('Swatches');\n});\n"
  },
  {
    "path": "__tests__/skpm/render-context.test.js",
    "content": "import * as React from 'react';\nimport * as sketch from 'sketch';\nimport { render, View, Text } from '../../lib';\n\n// depending on where those tests run, we don't get the things,\n// eg. the context might be empty or there is no selected document\n// This make sure we always get something\nfunction getDoc(document) {\n  return sketch.getSelectedDocument() || document;\n}\n\ntest('should render a Page with context events', (context, document) => {\n  const { selectedPage } = getDoc(document);\n  const Swatch = ({ hex }) => {\n    const [count, setCount] = React.useState(0);\n\n    React.useEffect(() => {\n      setCount(10);\n    }, [count]);\n\n    return (\n      <View\n        name={`Count is ${count}`}\n        style={{\n          height: 96,\n          width: 96,\n          margin: 4,\n          backgroundColor: hex,\n          padding: 8,\n        }}\n      >\n        <Text name=\"Swatch Name\" style={{ color: '#000', fontWeight: 'bold' }}>\n          Count is {count}\n        </Text>\n      </View>\n    );\n  };\n\n  render(<Swatch hex=\"#F3F4F4\" />, selectedPage);\n\n  expect(selectedPage.layers[0].name).toBe('Count is 10');\n});\n"
  },
  {
    "path": "__tests__/skpm/render-in-wrapped-object.test.js",
    "content": "import * as React from 'react';\nimport * as sketch from 'sketch';\nimport { render, View, Artboard, Text } from '../../lib';\n\n// depending on where those tests run, we don't get the things,\n// eg. the context might be empty or there is no selected document\n// This make sure we always get something\nfunction getDoc(document) {\n  return sketch.getSelectedDocument() || document;\n}\n\nconst colorList = {\n  Haus: '#F3F4F4',\n  Night: '#333',\n  Sur: '#96DBE4',\n  'Sur Dark': '#24828F',\n  Peach: '#EFADA0',\n  'Peach Dark': '#E37059',\n  Pear: '#93DAAB',\n  'Pear Dark': '#2E854B',\n};\n\ntest('should render a Page with a rectangle', (context, document) => {\n  const { selectedPage } = getDoc(document);\n  const Swatch = ({ name, hex }) => (\n    <View\n      name={`Swatch ${name}`}\n      style={{\n        height: 96,\n        width: 96,\n        margin: 4,\n        backgroundColor: hex,\n        padding: 8,\n      }}\n    >\n      <Text name=\"Swatch Name\" style={{ color: '#000', fontWeight: 'bold' }}>\n        {name}\n      </Text>\n      <Text name=\"Swatch Hex\" style={{ color: '#000' }}>\n        {hex}\n      </Text>\n    </View>\n  );\n\n  render(\n    <Artboard\n      name=\"Swatches\"\n      style={{\n        flexDirection: 'row',\n        flexWrap: 'wrap',\n        width: (96 + 8) * 4,\n      }}\n    >\n      {Object.keys(colorList).map(color => (\n        <Swatch name={color} hex={colorList[color]} key={color} />\n      ))}\n    </Artboard>,\n    selectedPage,\n  );\n\n  expect(selectedPage.layers[0].name).toBe('Swatches');\n});\n"
  },
  {
    "path": "book.json",
    "content": "{\n  \"gitbook\": \">= 3.2.1\",\n  \"title\": \"react-sketchapp\",\n  \"plugins\": [\n    \"edit-link\",\n    \"prism\",\n    \"-highlight\",\n    \"github\",\n    \"-search\",\n    \"codeblock-disable-glossary\",\n    \"anchorjs\"\n  ],\n  \"pluginsConfig\": {\n    \"edit-link\": {\n      \"base\": \"https://github.com/airbnb/react-sketchapp/tree/master\",\n      \"label\": \"Edit This Page\"\n    },\n    \"github\": {\n      \"url\": \"https://github.com/airbnb/react-sketchapp/\"\n    }\n  }\n}\n"
  },
  {
    "path": "docs/API.md",
    "content": "# API Reference\n\n- [`render`](#renderelement-container)\n- [`renderToJSON`](#rendertojsonelement)\n- [Components](#components)\n  - [`<Document>`](#document)\n  - [`<Page>`](#page)\n  - [`<Artboard>`](#artboard)\n  - [`<Image>`](#image)\n  - [`<RedBox>`](#redbox)\n  - [`<Svg>`](#svg)\n  - [`<Text>`](#text)\n  - [`<View>`](#view)\n- [`Hooks`](#hooks)\n  - [`useWindowDimensions`](#usewindowdimensions)\n- [`Platform`](#platform)\n  - [`OS`](#os)\n  - [`Version`](#version)\n  - [`select`](#selectobj)\n- [`StyleSheet`](#stylesheet)\n  - [`hairlineWidth`](#hairlinewidth)\n  - [`absoluteFill`](#absolutefill)\n  - [`create`](#createstyles)\n  - [`flatten`](#flattenstyles)\n  - [`resolve`](#resolvestyle)\n- [`TextStyles`](#textstyles)\n  - [`create`](#createstyleoptionsstyles)\n  - [`resolve`](#resolvestyle)\n- [`Symbols`](#symbols)\n  - [`makeSymbol`](#makesymbolnode-props-document)\n\n### `render(element, container)`\n\nReturns the top-level rendered Sketch object or an array of Sketch objects if you use `<Page>` components.\n\n#### Parameters\n\n##### `element` (required)\n\nTop-level React component that defines your Sketch document.\n\nExample:\n\n```js\n<Document>\n  <Page name=\"Mobile\">\n    <Artboard name=\"iPhone\">\n      <View>\n        <Text>Hello World</Text>\n      </View>\n    </Artboard>\n  </Page>\n</Document>\n```\n\n##### `container` (optional)\n\nThe element to render into - will be replaced. Should either be a Sketch [Document](https://developer.sketchapp.com/reference/api/#document), Sketch [Group](https://developer.sketchapp.com/reference/api/#group) or Sketch [Page](https://developer.sketchapp.com/reference/api/#page) Object.\n\nExample: `sketch.getSelectedDocument().selectedPage`.\n\n#### Returns\n\nThe top-most rendered native Sketch layer.\n\n#### Example\n\n```js\nimport sketch from 'sketch';\nimport { View, Text, render } from 'react-sketchapp';\n\nconst Document = props => (\n  <View>\n    <Text>Hello world!</Text>\n  </View>\n);\n\nexport default () => {\n  render(<Document />, sketch.getSelectedDocument().selectedPage);\n};\n```\n\n### `renderToJSON(element)`\n\nReturns a Sketch JSON object for further consumption - doesn't add to the page.\n\n#### Parameters\n\n##### `element` (required)\n\nTop-level React component that defines your Sketch document.\n\n#### Returns\n\nThe top-most Sketch layer as JSON.\n\n## Components\n\n### `<Document>`\n\nWrapper for Sketch's Documents. Must be used at the root of your application and is required if you would like to have multiple pages.\n\n#### Props\n\n| Prop       | Type   | Default | Note                                     |\n| ---------- | ------ | ------- | ---------------------------------------- |\n| `children` | `Node` |         | Can only be [`<Page>`](#page) components |\n\n#### Example\n\n```js\n<Document>\n  <Page>\n    <Text>Hello world!</Text>\n  </Page>\n  <Page>\n    <Text>Hello second world!!</Text>\n  </Page>\n</Document>\n```\n\n### `<Page>`\n\nWrapper for Sketch's Pages. Requires a [`<Document>`](#document) component as a parent if you would like to use multiple of these components.\n\n#### Props\n\n| Prop       | Type     | Default | Note                                             |\n| ---------- | -------- | ------- | ------------------------------------------------ |\n| `name`     | `String` |         | The name to be displayed in the Sketch Page List |\n| `children` | `Node`   |         |                                                  |\n\n#### Example\n\n```js\n<Page name=\"My Page\">\n  <Text>Hello world!</Text>\n</Page>\n```\n\n### `<Artboard>`\n\nWrapper for Sketch's Artboards. Requires a [`<Page>`](#page) component as a parent if you would like to use multiple of these components.\n\n#### Props\n\n| Prop | Type | Default | Note |\n| --- | --- | --- | --- |\n| `name` | `String` |  | The name to be displayed in the Sketch Layer List |\n| `children` | `Node` |  |  |\n| `style` | [`Style`](/docs/styling.md) |  |  |\n| `viewport` | `Viewport` |  | Object: { name: string, width: number, height: number, scale?: number, fontScale?: number } |\n| `isHome` | `Boolean` |  | Is prototype home screen if true |\n\nThe `scale` and `fontScale` attributes in the `viewport` prop are not used by Sketch, but can be used together with the [`useWindowDimensions`](#usewindowdimensions) hook for conditional styling/rendering.\n\n#### Examples\n\nHello world with width of 480px.\n\n```js\n<Artboard\n  name=\"My Artboard\"\n  style={{\n    width: 480,\n  }}\n>\n  <Text>Hello world!</Text>\n</Artboard>\n```\n\nMobile screen artboard with viewport preset (supports scrolling in prototypes).\n\n```js\n<Artboard\n  name=\"Home/Mobile\"\n  style={{\n    width: 360,\n    height: 1280,\n  }}\n  viewport={{\n    name: 'Mobile',\n    width: 360,\n    height: 640,\n  }}\n>\n  <Text>Hello world!</Text>\n</Artboard>\n```\n\n### `<Image>`\n\n#### Props\n\n| Prop         | Type                        | Default   | Note |\n| ------------ | --------------------------- | --------- | ---- |\n| `children`   | `Node`                      |           |      |\n| `source`     | `ImageSource`               |           |      |\n| `style`      | [`Style`](/docs/styling.md) |           |      |\n| `resizeMode` | `ResizeMode`                | `contain` |      |\n\n```js\ntype ImageSource = string | { src: string };\ntype ResizeMode = 'contain' | 'cover' | 'stretch' | 'center' | 'repeat' | 'none';\n```\n\n#### Example\n\n```js\n<Image\n  source=\"http://placekitten.com/400\"\n  resizeMode=\"contain\"\n  style={{\n    height: 400,\n    width: 400,\n  }}\n/>\n```\n\n### `<RedBox>`\n\nA red box / 'red screen of death' error handler. Thanks to [commissure/redbox-react](https://github.com/commissure/redbox-react).\n\n#### Props\n\n| Prop | Type | Default | Note |\n| --- | --- | --- | --- |\n| `error` | [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) | **required** | A JavaScript Error object |\n\n#### Example\n\n```js\nimport sketch from 'sketch';\nimport { RedBox, render } from 'react-sketchapp';\n\nexport default () => {\n  const { selectedPage } = sketch.getSelectedDocument();\n  try {\n    render(<BrokenComponent />, selectedPage);\n  } catch (err) {\n    render(<RedBox error={err} />, selectedPage);\n  }\n};\n```\n\n### `<Svg>`\n\nSVG Interface to Sketch\n\nThe API is based on [`react-native-svg`](https://github.com/react-native-community/react-native-svg). See more information on [its README](https://github.com/react-native-community/react-native-svg#Usage).\n\n#### Example\n\n```js\nimport sketch from 'sketch';\nimport { Svg, render } from 'react-sketchapp';\n\nexport default () => {\n  render(\n    <Svg xmlns=\"http://www.w3.org/2000/svg\" width=\"494\" height=\"447\" viewBox=\"0 0 494 447\">\n      <Svg.G fill=\"none\" fillRule=\"evenodd\">\n        <Svg.Path fill=\"#FFAE00\" d=\"M247 447L0 160 107 15 247 0l140 15 107 145\" />\n        <Svg.Path fill=\"#EC6C00\" d=\"M247 447L0 160h494\" />\n        <Svg.Path fill=\"#FFAE00\" d=\"M247 447L100 160h294\" />\n        <Svg.Path fill=\"#FFEFB4\" d=\"M247 0L100 160h294\" />\n        <Svg.Path fill=\"#FFAE00\" d=\"M107 15L52 88 0 160h101M387 15l55 73 52 72H393\" />\n        <Svg.Path fill=\"#FED305\" d=\"M107 15l-7 145L247 0m140 15l7 145L247 0\" />\n      </Svg.G>\n    </Svg>,\n    sketch.getSelectedDocument().selectedPage,\n  );\n};\n```\n\n#### Direct imports\n\nAdditionally, to have a somewhat more compliant mode to the `react-native-svg` API, the SVG components might as well be imported directly:\n\n```js\nimport sketch from 'sketch';\nimport { render } from 'react-sketchapp';\nimport Svg, { G, Path } from 'react-sketchapp/lib/components/Svg';\n\nexport default () => {\n  render(\n    <Svg xmlns=\"http://www.w3.org/2000/svg\" width=\"494\" height=\"447\" viewBox=\"0 0 494 447\">\n      <G fill=\"none\" fillRule=\"evenodd\">\n        <Path fill=\"#FFAE00\" d=\"M247 447L0 160 107 15 247 0l140 15 107 145\" />\n        <Path fill=\"#EC6C00\" d=\"M247 447L0 160h494\" />\n        <Path fill=\"#FFAE00\" d=\"M247 447L100 160h294\" />\n        <Path fill=\"#FFEFB4\" d=\"M247 0L100 160h294\" />\n        <Path fill=\"#FFAE00\" d=\"M107 15L52 88 0 160h101M387 15l55 73 52 72H393\" />\n        <Path fill=\"#FED305\" d=\"M107 15l-7 145L247 0m140 15l7 145L247 0\" />\n      </G>\n    </Svg>,\n    sketch.getSelectedDocument().selectedPage,\n  );\n};\n```\n\n### `<Text>`\n\nText primitives\n\n#### Props\n\n| Prop | Type | Default | Note |\n| --- | --- | --- | --- |\n| `name` | `String` |  | The name to be displayed in the Sketch Layer List |\n| `children` | `String` |  |  |\n| `style` | [`Style`](/docs/styling.md) |  |  |\n\n#### Example\n\n```js\n<Text\n  name=\"Sketch Layer name\"\n  style={{\n    fontSize: 24,\n    fontFamily: 'Helvetica',\n    fontWeight: 'bold',\n    color: '#01ffae',\n  }}\n>\n  Hello World!\n</Text>\n```\n\n### `<View>`\n\nView primitives\n\n#### Props\n\n| Prop | Type | Default | Note |\n| --- | --- | --- | --- |\n| `name` | `String` |  | The name to be displayed in the Sketch Layer List |\n| `children` | `Node` |  |  |\n| `style` | [`Style`](/docs/styling.md) |  |  |\n| `flow` | `Flow` |  | Object: { target: string, targetId: string, animationType: string } |\n\n#### Examples\n\n##### Example with children\n\n```js\n<View\n  name=\"Sketch Layer name\"\n  style={{\n    flexDirection: 'row',\n    width: 480,\n    backgroundColor: '#01ffae',\n  }}\n>\n  <Text>Hello World!</Text>\n  <Text>Hello World!</Text>\n  <Text>Hello World!</Text>\n</View>\n```\n\n##### Example using `flow` prop for prototyping destination\n\n```js\n<Document>\n  <Artboard name=\"Home\">\n    <View\n      name=\"Menu Button\"\n      style={{\n        height: 100,\n        backgroundColor: '#01ffae',\n      }}\n      flow={{\n        target: 'menu', // From <Artboard name\" or can be \"back\"\n        // targetId: uuid (can be used to reference existing artboards/uuids)\n        // animationType: string (constants can be used from require('sketch') API, or hardcoded)\n      }}\n    >\n      <Text>Open menu!</Text>\n    </View>\n  </Artboard>\n  <Artboard name=\"Menu\">\n    <View name=\"Go back\" flow={{ target: 'back' }} /* \"back\" used instead of <Artboard> id */>\n      <Text>Go back!</Text>\n    </View>\n  </Artboard>\n</Document>\n```\n\n## Hooks\n\n### `useWindowDimensions()`\n\nReturns the window dimensions of the parent `<Artboard>`. Returns `{ width: number, height: number, fontScale: number, scale: number }`.\n\n#### Example\n\n```js\nimport { Page, Artboard, View, Text, useWindowDimensions } from 'react-sketchapp';\n\nconst HomePage = () => {\n  const { height, width } = useWindowDimensions();\n\n  return (\n    <View style={{ flex: 1 }}>\n      <View style={{ height, width }}>\n        <Text>Hello World</Text>\n      </View>\n      {(width >= 768) && (\n        <View style={{ height, width, backgroundColor: 'blue' }}>\n          <Text style={{ color: 'white' }}>\n            You can only see this text on tablet/desktop\n          </Text>\n        </View>\n      )}\n    </View>\n  );\n};\n\nconst devices = [{\n  name: 'Mobile',\n  width: 360,\n  height: 640,\n}, {\n  name: 'Tablet',\n  width: 768\n  height: 1024,\n}, {\n  name: 'Desktop',\n  width: 1024\n  height: 1280,\n}];\n\nrender(\n  <Page style={{ flexDirection: 'row' }}>\n    {devices.map(viewport => (\n      <Artboard viewport={viewport} style={{ marginRight: 80 }}>\n        <HomePage />\n      </Artboard>\n    ))}\n  </Page>,\n);\n```\n\n## Platform\n\n### `OS`\n\n`sketch`\n\n### `Version`\n\n`1`\n\n### `select(obj)`\n\n#### Parameters\n\n##### `obj`\n\n## StyleSheet\n\nCompared to single-use `style` objects, `StyleSheets` enable creation of re-usable, optimized style references.\n\n### `hairlineWidth`\n\nThe platform's global 'hairline width'.\n\n### `absoluteFill`\n\nA constant 'absolute fill' style.\n\n### `create(styles)`\n\nCreate an optimized `StyleSheet` reference from a style object.\n\n#### Parameters\n\n##### `styles`\n\n#### Example\n\n```js\nconst styles = StyleSheet.create({\n  foo: {\n    fontSize: 24,\n    color: 'red',\n  },\n  bar: {\n    fontSize: 36,\n    color: 'blue',\n  },\n});\n// { foo: 1, bar: 2 }\n\n<View>\n  <Text style={styles.foo} />\n  <Text style={styles.bar} />\n</View>;\n```\n\n### `flatten(styles)`\n\nFlatten an array of style objects into one aggregated object, **or** look up the definition for a registered stylesheet.\n\n#### Parameters\n\n##### `styles`\n\n#### Example\n\n```js\nconst styles = StyleSheet.create({\n  foo: {\n    fontSize: 24,\n    color: 'red',\n  },\n  bar: {\n    backgroundColor: 'blue',\n    lineHeight: 36,\n  },\n});\n\nStyleSheet.flatten([styles.foo, styles.bar]);\n// { fontSize: 24, color: 'red',  backgroundColor: 'blue', lineHeight: 36 }\n\n// alternatively:\nStyleSheet.flatten(styles.foo);\n// { fontSize: 24, color: 'red' }\n```\n\n### `resolve(style)`\n\nResolve one style.\n\n#### Parameters\n\n##### `style`\n\n#### Example\n\n```js\nconst styles = StyleSheet.create({\n  foo: {\n    fontSize: 24,\n    color: 'red',\n  },\n});\n\nStyleSheet.resolve(styles.foo);\n// { fontSize: 24, color: 'red' }\n```\n\n## TextStyles\n\nAn interface to Sketch's shared text styles. Create styles with or without rendering them to the document canvas.\n\n### `create(styles, options)`\n\nThe primary interface to TextStyles. **Call this before rendering**.\n\n#### Parameters\n\n##### `styles` **(required)**\n\nAn object of JavaScript styles. The keys will be used as Sketch's Text Style names.\n\n##### `options: { document, clearExistingStyles }`\n\n###### `document`\n\nThe Sketch Document currently being rendered into.\n\n###### `clearExistingStyles`\n\nClear any styles already registered in the document.\n\n#### Example\n\n```js\nimport sketch from 'sketch';\nimport { TextStyles, View, Text, render } from 'react-sketchapp';\n\nexport default () => {\n  const typeStyles = {\n    Headline: {\n      fontSize: 36,\n      fontFamily: 'Apercu',\n      lineHeight: 38,\n    },\n    Body: {\n      fontSize: 16,\n      fontFamily: 'Helvetica',\n      lineHeight: 22,\n    },\n  };\n\n  TextStyles.create(\n    {\n      context: context,\n      clearExistingStyles: true,\n    },\n    typeStyles,\n  );\n\n  const Document = () => (\n    <View>\n      <Text style={typeStyles.Headline}>Headline text</Text>\n      <Text style={typeStyles.Body}>Body text</Text>\n    </View>\n  );\n\n  render(<Document />, sketch.getSelectedDocument().selectedPage);\n};\n```\n\n### `resolve(style)`\n\nFind a stored native Sketch style object for a given JavaScript style object. You probably don't need to use this.\n\n#### Parameters\n\n##### `style`\n\nA JavaScript style\n\n### `styles`\n\nFind all of the registered styles. You probably don't need to use this.\n\n### `get(name)`\n\nFind a text style by _name_.\n\n#### Parameters\n\n##### `name`\n\nThe style name\n\n#### Example\n\n```js\nimport sketch from 'sketch';\nimport { TextStyles, View, Text, render } from 'react-sketchapp';\n\nexport default () => {\n  const typeStyles = {\n    Headline: {\n      fontSize: 36,\n      fontFamily: 'Apercu',\n      lineHeight: 38,\n    },\n    Body: {\n      fontSize: 16,\n      fontFamily: 'Helvetica',\n      lineHeight: 22,\n    },\n  };\n\n  TextStyles.create(\n    {\n      context: context,\n      clearExistingStyles: true,\n    },\n    typeStyles,\n  );\n\n  const Document = () => (\n    <View>\n      <Text style={TextStyles.get('Headline')}>Headline text</Text>\n      <Text style={TextStyles.get('Body')}>Body text</Text>\n    </View>\n  );\n\n  render(<Document />, sketch.getSelectedDocument().selectedPage);\n};\n```\n\n### `clear`\n\nReset the registered styles.\n\n## Symbols\n\nAn interface to Sketch's symbols. Create symbols and optionally inject them into the symbols page.\n\n### `makeSymbol(node, props, document)`\n\nCreates a new symbol and injects it into the `Symbols` page. The name of the symbol can be optionally provided and will default to the display name of the component.\n\nReturns a react component which is an can be used to render instances of the symbol.\n\n#### Parameters\n\n| Parameter | Type | Default | Note |\n| --- | --- | --- | --- |\n| `node` | `Node` |  | The node object that will be rendered as a symbol |\n| `props` | `Object` | The node name | Optional name for the symbol, string can include backslashes to organize these symbols with Sketch. For example `squares/blue` |\n| `props.name` | `String` | The node name | Optional name for the symbol, string can include backslashes to organize these symbols with Sketch. For example `squares/blue` |\n| `props.style` | [`Style`](/docs/styling.md) |  |  |\n| `document` | `Object` | The current document | The Sketch document to make the symbol in |\n\n### `getSymbolComponentByName(name)`\n\nReturns a react component which can be used to render the symbol instance that is associated with that name.\n\n### `getSymbolMasterByName(name)`\n\nReturns the JSON representation of the symbol master that is associated with that name.\n\n### Symbol example\n\n```js\nimport sketch from 'sketch';\nimport { View, makeSymbol, Artboard, render } from 'react-sketchapp';\n\nconst BlueSquare = () => (\n  <View name=\"Blue Square\" style={{ width: 100, height: 100, backgroundColor: 'blue' }} />\n);\n\nconst BlueSquareSymbol = makeSymbol(BlueSquare);\n\nconst Document = () => (\n  <Artboard>\n    <BlueSquareSymbol />\n  </Artboard>\n);\n\nexport default () => {\n  render(<Document />, sketch.getSelectedDocument().selectedPage);\n};\n```\n\n### Text override example\n\nText overrides use the name parameter to target a specific Text primitive. When no name is given the value within the Text primitive can be used to override the value.\n\n```js\nimport sketch from 'sketch';\nimport { View, Text, makeSymbol, Artboard, render } from 'react-sketchapp';\n\nconst BlueSquare = () => (\n  <View name=\"Blue Square\" style={{ width: 100, height: 100, backgroundColor: 'blue' }}>\n    <Text>Blue Square Text</Text>\n  </View>\n);\n\nconst BlueSquareSymbol = makeSymbol(BlueSquare, 'squares/blue');\n\nconst Document = () => (\n  <Artboard>\n    <BlueSquareSymbol\n      overrides={{\n        'Blue Square Text': 'Override Text',\n      }}\n    />\n  </Artboard>\n);\n\nexport default () => {\n  render(<Document />, sketch.getSelectedDocument().selectedPage);\n};\n```\n\n### Image override example\n\nImage overrides use the name parameter to target a specific Image primitive.\n\n```js\nimport sketch from 'sketch';\nimport { View, Image, Artboard, makeSymbol, render } from 'react-sketchapp';\n\nconst BlueSquare = () => (\n  <View name=\"Blue Square\" style={{ width: 100, height: 100, backgroundColor: 'blue' }}>\n    <Image name=\"Blue Square Image\" source=\"https://hello.world/image.jpg\" />\n  </View>\n);\n\nconst BlueSquareSymbol = makeSymbol(BlueSquare, 'squares/blue');\n\nconst Document = () => (\n  <Artboard>\n    <BlueSquareSymbol\n      overrides={{\n        'Blue Square Image': 'https://hello.world/different.jpg',\n      }}\n    />\n  </Artboard>\n);\n\nexport default () => {\n  render(<Document />, sketch.getSelectedDocument().selectedPage);\n};\n```\n\n#### Nested symbol + override example\n\n```js\nimport sketch from 'sketch';\nimport { View, Text, makeSymbol, Image, Artboard, render } from 'react-sketchapp';\n\nconst RedSquare = () => (\n  <View name=\"Red Square\" style={{ width: 100, height: 100, backgroundColor: 'red' }}>\n    <Text name=\"Red Square Text\">Red Square</Text>\n  </View>\n);\n\nconst RedSquareSymbol = makeSymbol(RedSquare, 'squares/red');\n\nconst BlueSquare = () => (\n  <View name=\"Blue Square\" style={{ width: 100, height: 100, backgroundColor: 'blue' }}>\n    <Text name=\"Blue Square Text\">Blue Square</Text>\n  </View>\n);\n\nconst BlueSquareSymbol = makeSymbol(BlueSquare, 'squares/blue');\n\nconst Photo = () => (\n  <Image\n    name=\"Photo\"\n    source=\"https://pbs.twimg.com/profile_images/895665264464764930/7Mb3QtEB_400x400.jpg\"\n    style={{ width: 100, height: 100 }}\n  />\n);\n\nconst PhotoSymbol = makeSymbol(Photo);\n\nconst Nested = () => (\n  <View name=\"Nested\" style={{ display: 'flex', flexDirection: 'column', width: 75, height: 150 }}>\n    <PhotoSymbol name=\"Photo Instance\" style={{ width: 75, height: 75 }} />\n    <RedSquareSymbol name=\"Red Square Instance\" style={{ width: 75, height: 75 }} />\n  </View>\n);\n\nconst NestedSymbol = makeSymbol(Nested);\n\nconst Document = () => (\n  <Artboard style={{ display: 'flex' }}>\n    <NestedSymbol\n      name=\"Nested Symbol\"\n      style={{ width: 75, height: 150 }}\n      overrides={{\n        'Red Square Instance': BlueSquareSymbol,\n        'Blue Square Text': 'Text override',\n        Photo: 'https://pbs.twimg.com/profile_images/833785170285178881/loBb32g3.jpg',\n      }}\n    />\n  </Artboard>\n);\n\nexport default () => {\n  render(<Document />, sketch.getSelectedDocument().selectedPage);\n};\n```\n"
  },
  {
    "path": "docs/FAQ.md",
    "content": "# Frequently Asked Questions\n\n#### Why?!??!\n\n`react-sketchapp` evolved out of our need to generate **high-quality, consistent Sketch assets** for our design system at Airbnb. Wrapping Sketch’s imperative API is a pragmatic solution for a great developer experience and predictable rendering.\n\n#### How do I `console.log`?\n\nYou have multiple options to view the logs:\n\n- Using the [sketch-dev-tools](https://github.com/skpm/sketch-dev-tools)\n- `Console.app -> ~/Library/Logs -> com.bohemiancoding.sketch -> Plugin Output.log`\n- in the terminal\n\n  ```bash\n  skpm log -f\n  ```\n\n- in the terminal\n\n  ```bash\n  tail -F ~/Library/Logs/com.bohemiancoding.sketch3/Plugin\\ Output.log\n  ```\n\n  Occasionally this file disappears — in that case, run this and then try `tail`ing again.\n\n  ```bash\n  touch ~/Library/Logs/com.bohemiancoding.sketch3/Plugin\\ Output.log\n  ```\n\nFor more information, check out the [Sketch developer documentation](https://developer.sketch.com/plugins/debugging).\n\n#### I'm running a project as a plugin & Sketch isn't showing my changes\n\nSketch has a [developer mode](https://developer.sketch.com/plugins/debugging#reload-scripts) which refreshes plugins before running. If you're using `skpm` this should be set up automatically, but just in case try running\n\n```bash\ndefaults write com.bohemiancoding.sketch3.plist AlwaysReloadScript -bool YES\n```\n\n#### `<View>` & `<Text>`? Where are the shapes? Talk to me about your API decisions!\n\nEarly versions of `react-sketchapp` mirrored Sketch's layers — `<Rect>`, `<Oval>`, `<Star>` etc. This was adequate for rendering simplistic designs such as grids of color palettes, but our focus is on production design systems.\n\nAt some point, we had to translate from our component codebase's primitives to Sketch's shapes. We tried translating trees of React Native elements into `<Rect>`s etc, but it felt clumsy. Not every Sketch property has an analog in react-native, but **most react-native properties are translatable to Sketch**.\n\nBy aligning with react-native's API we:\n\n- think in the same primitives as we actually use in production\n- use the same layout algorithm in design & code\n- [render real components](http://airbnb.io/react-sketchapp/docs/guides/universal-rendering.html) into Sketch with `react-primitives` (a platform independent set of primitives)\n\nWhere it makes sense we're open to creating Sketch-specific components —there's no analog for `<Artboard>` on web or mobile—but the goal of `react-sketchapp` is to bring design & engineering closer together.\n\n#### So I can't draw arbitrary shapes?\n\nYou can use the [SVG API](/docs/API.md#svg) to draw arbitrary shapes.\n\n#### Any plans to support Sketch's constraints for layout?\n\nNot currently. FlexBox is the closest we have to a predictable, cross-platform layout specification — by using it, we can use the same styles on every platform we build for.\n\nWe currently use [`yoga`](https://github.com/facebook/yoga).\n\n#### Is there two-way binding? Can I generate React components from Sketch? 🔁\n\nNope.\n\nIsomorphisms are compelling but our focus is on tools that we can use day-to-day to improve the productivity of designers and engineers working on large-scale production applications.\n\nGetting production-ready semantics out of Sketch is more difficult than generating production-ready Sketch templates from React components 💀\n\nOur solution is to keep our [our design system](http://airbnb.design/building-a-visual-language/)’s source of truth in code, and use `react-sketchapp` to compose & consume it.\n\nTo _edit_ our design system, we are free to leverage any technology that can create React components, or be compiled to JSX, such as:\n\n- [React-centric IDEs](https://www.decosoftware.com/)\n- in-house design tools that are tailored to our workflow (whilst being backed by data, version control & semantic versioning) 🔜 👀\n- writing React components in text editors with our fingers\n\n#### Does this tie your workflow to Sketch? What about other design tools?\n\nTreating Sketch primarily as a _rendering target_ for cross-platform components pushes you to store components & style in code — you're then free to build translation layers for any other design tool that exposes an API.\n\nGiven equivalent API support it would be possible to simultaneously render to `react-sketchapp`, `react-figma`, `react-xd` & `react-quark`.\n\nRather than tying us into one design tools, reasoning about design in cross-platform primitives _frees us_ to use the tooling we want.\n\n#### Can I use [TypeScript](https://www.typescriptlang.org/)?\n\nOf course!\n\nTypeScript definitions are published with the npm package.\n"
  },
  {
    "path": "docs/README.md",
    "content": "## Table of Contents\n\n- [Introduction](/README.md)\n- [Guides](/docs/guides/README.md)\n  - [Getting Started](/docs/guides/getting-started.md)\n  - [Using `skpm` as a build system](/docs/guides/using-skpm.md)\n  - [Rendering](/docs/guides/rendering.md)\n  - [Data Fetching](/docs/guides/data-fetching.md)\n  - [Universal Rendering](/docs/guides/universal-rendering.md)\n  - [Styling](/docs/guides/styling.md)\n- [API Reference](/docs/API.md)\n  - [render](/docs/API.md#renderelement-container)\n  - [renderToJSON](/docs/API.md#rendertojsonelement)\n  - [Document](/docs/API.md#document)\n  - [Page](/docs/API.md#page)\n  - [Artboard](/docs/API.md#artboard)\n  - [Image](/docs/API.md#image)\n  - [RedBox](/docs/API.md#redbox)\n  - [Svg](/docs/API.md#svg)\n  - [Text](/docs/API.md#text)\n  - [View](/docs/API.md#view)\n  - [Platform](/docs/API.md#platform)\n  - [StyleSheet](/docs/API.md#stylesheet)\n  - [TextStyles](/docs/API.md#textstyles)\n  - [Symbols](/docs/API.md#symbols)\n- [Examples](/docs/examples.md)\n- [Change Log](/CHANGELOG.md)\n- [FAQ](/docs/FAQ.md)\n- [Contributing](https://github.com/airbnb/react-sketchapp/blob/master/.github/CONTRIBUTING.md)\n"
  },
  {
    "path": "docs/examples.md",
    "content": "# Examples\n\n`react-sketchapp` is bundled with lots of examples!\n\n### [Basic setup](https://github.com/airbnb/react-sketchapp/tree/master/examples/basic-setup)\n\n![Basic setup](https://cloud.githubusercontent.com/assets/591643/24778192/1f0684ec-1ade-11e7-866b-b11bb60ac109.png)\n\n### [Style guide](https://github.com/airbnb/react-sketchapp/tree/master/examples/styleguide)\n\n![Style guide](https://cloud.githubusercontent.com/assets/591643/24778196/2a4ef41a-1ade-11e7-9805-8d974bbfd708.png)\n\n### [Profile Cards](https://github.com/airbnb/react-sketchapp/tree/master/examples/profile-cards)\n\n![examples-profile-cards](https://cloud.githubusercontent.com/assets/591643/24778173/0dd7c03c-1ade-11e7-8bad-1ad51fe1033e.png)\n\n### [Profile Cards on Web + Sketch w/ `react-primitives`](https://github.com/airbnb/react-sketchapp/tree/master/examples/profile-cards-primitives)\n\n![examples-primitives](https://cloud.githubusercontent.com/assets/591643/24778174/0dd9d214-1ade-11e7-9372-fa8b578a0b48.png)\n\n### [Profile Cards w/ `react-with-styles`](https://github.com/airbnb/react-sketchapp/tree/master/examples/profile-cards-react-with-styles)\n\n![examples-primitives](https://cloud.githubusercontent.com/assets/591643/24778174/0dd9d214-1ade-11e7-9372-fa8b578a0b48.png)\n\n### [Profile Cards w/ GraphQL](https://github.com/airbnb/react-sketchapp/tree/master/examples/profile-cards-graphql)\n\n![Profile Cards w/ GraphQL](https://cloud.githubusercontent.com/assets/591643/24778175/0dda21d8-1ade-11e7-9545-13b472263ff6.png)\n\n### [Venue Search on Web + Sketch w/ `react-primitives`, Foursquare & Google Maps](https://github.com/airbnb/react-sketchapp/tree/master/examples/foursquare-maps)\n\n![foursquare-maps](https://cloud.githubusercontent.com/assets/591643/25052095/f666928e-2104-11e7-805c-a3c73ffcabcb.png)\n\n### [Generative Colors w/ Chroma-JS](https://github.com/airbnb/react-sketchapp/tree/master/examples/colors)\n\n![examples-colors](https://cloud.githubusercontent.com/assets/591643/24778153/efc76cdc-1add-11e7-93dd-0351f8f428c0.png)\n\n### [Timeline w/ AirTable](https://github.com/airbnb/react-sketchapp/tree/master/examples/timeline-airtable)\n\n![timeline-AirTable](https://cloud.githubusercontent.com/assets/21080/25830456/cdc67bf8-3411-11e7-8998-fdef507ab0d2.png)\n\n### [Basic setup w/ Typescript](https://github.com/airbnb/react-sketchapp/tree/master/examples/basic-setup-typescript)\n\n![typings](./assets/tooling-typings-vs-code.png) ![examples-basic](https://cloud.githubusercontent.com/assets/591643/24778192/1f0684ec-1ade-11e7-866b-b11bb60ac109.png)\n"
  },
  {
    "path": "docs/guides/README.md",
    "content": "# Guides\n\nHow to use `react-sketchapp` for fun and profit.\n\n- [Getting Started](getting-started.md)\n- [Using `skpm` as a build system](using-skpm.md)\n- [Rendering](rendering.md)\n- [Data Fetching](data-fetching.md)\n- [Universal Rendering](universal-rendering.md)\n- [Styling](styling.md)\n"
  },
  {
    "path": "docs/guides/data-fetching.md",
    "content": "# Data Fetching\n\nPull real data from an API with `fetch` or GraphQL.\n\n## Fetch\n\n[Full example](https://github.com/airbnb/react-sketchapp/tree/master/examples/foursquare-maps)\n\n`skpm` automatically provides the [Sketch `fetch` polyfill](https://github.com/skpm/sketch-polyfill-fetch) — just use `fetch` as usual.\n\n```js\nimport fetch from 'sketch-module-fetch-polyfill';\nimport { render } from 'react-sketchapp';\nimport MyApp from './MyApp';\n\nexport default context => {\n  fetch('https://reqres.in/api/users')\n    .then(res => res.json())\n    .then(data => {\n      render(<MyApp users={data.users} />, context.document.currentPage());\n    });\n};\n```\n\n## GraphQL\n\n[Full example](https://github.com/airbnb/react-sketchapp/tree/master/examples/profile-cards-graphql)\n\n[`gql-sketch`](https://github.com/jongold/gql-sketch) provides a convenient interface for interacting with GraphQL APIs.\n\n```bash\nnpm install gql-sketch --save\n```\n\n```js\nimport Client from 'gql-sketch';\nimport { render } from 'react-sketchapp';\nimport MyApp from './MyApp';\n\nexport default context => {\n  Client('http://example.com/my-graphql-endpoint')\n    .query(\n      `\n    {\n      allFilms {\n        films {\n          title,\n          actor,\n          catchphrase\n        }\n      }\n    }\n  `,\n    )\n    .then(({ allFilms }) => {\n      render(<MyApp films={allFilms} />, context.document.currentPage());\n    });\n};\n```\n"
  },
  {
    "path": "docs/guides/getting-started.md",
    "content": "# Getting Started\n\nYou can create a `react-sketchapp` project with `skpm`, by cloning a ready-made [example](../examples.md), or by manually setting up the `package.json` and `manifest.json` scripts (advanced usage).\n\n## Environment Setup\n\nYou will need npm, Node and Sketch.\n\n- Terminal (if you’re new to the command line, this [guide](https://medium.com/32pixels/the-designers-guide-to-the-osx-command-prompt-71b0016cac31) may help)\n  - You need to make sure `git` is installed – type `git --version` in your Terminal to check if it's installed, if it isn’t, you should be prompted to install via “command line developer tools”.\n- Code editor e.g. [VSCode](https://code.visualstudio.com/), [Atom](https://atom.io/)\n- Node.js & `npm` – [install with Homebrew](https://nodejs.org/en/download/package-manager/#macos) (or install with [Node Version Manager](https://nodejs.org/en/download/package-manager/#nvm))\n- [Sketch](https://www.sketch.com/)\n  - requires macOS\n\n## Creating a Project With Skpm\n\n**Replace** `my-app` with your desired project name:\n\n### Installation\n\n```bash\nnpm install --global skpm\nskpm create my-app --template=airbnb/react-sketchapp # template is a GitHub repo\ncd my-app\n```\n\n### Setup\n\nYou can now open `my-app` in your code editor of choice. You will see a `src` folder with a `manifest.json` file and Sketch entrypoint (e.g. `my-command.js`). If you wish to rename `my-command.js`, you can do so and update the file name in `script` in `manifest.json`\n\nExample modifications (assuming we want to rename the entrypoint file to `main.js` and don't want to have sub-commands):\n\n`src/manifest.json`\n\n```diff\n  \"commands\": [\n    {\n-      \"name\": \"my-command\",\n+      \"name\": \"My App Name: Sketch Components\"\n-      \"identifier\": \"my-command-identifier\",\n+      \"identifier\": \"main\",\n-      \"script\": \"./my-command.js\"\n+      \"script\": \"./main.js\"\n    }\n  ],\n  \"menu\": {\n-    \"title\": \"my-app\",\n-    \"items\": [\n-      \"my-command-identifier\"\n-    ]\n+    \"isRoot\": true,\n+    \"items\": [\n+      \"main\"\n+    ]\n+  }\n  }\n```\n\n### Rendering to Sketch\n\nTo render your app to Sketch, open the Sketch application, create a new blank document, then go to your Terminal and run:\n\n```bash\n# Make sure you've already done `cd my-app`\nnpm run render\n```\n\nYou can pass the target Sketch container layer (i.e. document, group or page object) to the `render` function in your Sketch plugin entrypoint file, using the Sketch API: `render(<App />, sketch.getSelectedDocument()`.\n\nFor more info on rendering to Sketch, see the [rendering](./rendering.md) page.\n"
  },
  {
    "path": "docs/guides/rendering.md",
    "content": "# Rendering Guide\n\nYou can use the Sketch API to select Sketch containers such as documents, pages or groups, to pass through to the `render` function.\n\n### Rendering to Multiple Pages or New Documents\n\n`src/my-command.js` (or whatever file your Sketch plugin entrypoint is).\n\n```js\nimport React from 'react';\nimport { render, Document, Page } from 'react-sketchapp';\n\n// <Document> wrapper is required if you want to use multiple pages\nconst App = () => (\n  <Document>\n    <Page name=\"Page 1\">\n      <Artboard>\n        <Text>Hello World!</Text>\n      </Artboard>\n    </Page>\n    <Page name=\"Page 2\">\n      <Artboard>\n        <Text>Hello World, again!</Text>\n      </Artboard>\n    </Page>\n  </Document>\n);\n\nexport default () => {\n  const documents = sketch.getDocuments();\n  const document =\n    sketch.getSelectedDocument() || new sketch.Document(); // get the current document // or create a new document\n};\n```\n\n## Rendering to Selected Document\n\nThis will render to the last active document. If there is no document open, document will be undefined and you will get an error, so you can add `|| new sketch.Document()` as a fallback to handle this.\n\n```js\nimport sketch from 'sketch';\nimport { render } from 'react-sketchapp';\n\n// const App = () => ... or import App from './App';\n\nexport default () => {\n  const document = sketch.getSelectedDocument();\n\n  render(<App />, document);\n};\n```\n\n## Rendering to Document by Name\n\nWe can select a document by name, by looping through `sketch.getDocuments()` and checking `doc.path` inside the loop.\n\n```js\nimport path from 'path';\nimport sketch from 'sketch';\nimport { render } from 'react-sketchapp';\n\n// const App = () => ... or import App from './App';\n\nconst getDocumentByName = name => {\n  return (sketch.getDocuments() || []).find(doc => {\n    return doc.path && path.basename(doc.path, '.sketch') === name;\n  });\n};\n\nexport default () => {\n  const document = getDocumentByName('My App Design') || new sketch.Document(); // Fallback to new document if document not found\n\n  render(<App />, document);\n};\n```\n"
  },
  {
    "path": "docs/guides/styling.md",
    "content": "# Styling\n\nComponents use CSS styles + FlexBox layout.\n\n## Layout Styles\n\n| property | type | supported? |\n| --- | --- | --- |\n| `width` | `number` &#124; `percentage` | ✅ |\n| `height` | `number` &#124; `percentage` | ✅ |\n| `top` | `number` &#124; `percentage` | ✅ |\n| `left` | `number` &#124; `percentage` | ✅ |\n| `right` | `number` &#124; `percentage` | ✅ |\n| `bottom` | `number` &#124; `percentage` | ✅ |\n| `minWidth` | `number` &#124; `percentage` | ✅ |\n| `maxWidth` | `number` &#124; `percentage` | ✅ |\n| `minHeight` | `number` &#124; `percentage` | ✅ |\n| `maxHeight` | `number` &#124; `percentage` | ✅ |\n| `margin` | `number` &#124; `percentage` | ✅ |\n| `marginVertical` | `number` &#124; `percentage` | ✅ |\n| `marginHorizontal` | `number` &#124; `percentage` | ✅ |\n| `marginTop` | `number` &#124; `percentage` | ✅ |\n| `marginBottom` | `number` &#124; `percentage` | ✅ |\n| `marginLeft` | `number` &#124; `percentage` | ✅ |\n| `marginRight` | `number` &#124; `percentage` | ✅ |\n| `padding` | `number` &#124; `percentage` | ✅ |\n| `paddingVertical` | `number` &#124; `percentage` | ✅ |\n| `paddingHorizontal` | `number` &#124; `percentage` | ✅ |\n| `paddingTop` | `number` &#124; `percentage` | ✅ |\n| `paddingBottom` | `number` &#124; `percentage` | ✅ |\n| `paddingLeft` | `number` &#124; `percentage` | ✅ |\n| `paddingRight` | `number` &#124; `percentage` | ✅ |\n| `borderWidth` | `number` &#124; `percentage` | ✅ |\n| `borderTopWidth` | `number` &#124; `percentage` | ✅ |\n| `borderRightWidth` | `number` &#124; `percentage` | ✅ |\n| `borderBottomWidth` | `number` &#124; `percentage` | ✅ |\n| `borderLeftWidth` | `number` &#124; `percentage` | ✅ |\n| `position` | `absolute` &#124; `relative` | ✅ |\n| `flexDirection` | `row` &#124; `row-reverse` &#124; `column` &#124; `column-reverse` | ✅ |\n| `flexWrap` | `wrap` &#124; `nowrap` | ✅ |\n| `justifyContent` | `flex-start` &#124; `flex-end` &#124; `center` &#124; `space-between` &#124; `space-around` | ✅ |\n| `alignItems` | `flex-start` &#124; `flex-end` &#124; `center` &#124; `stretch` | ✅ |\n| `alignSelf` | `auto` &#124; `flex-start` &#124; `flex-end` &#124; `center` &#124; `stretch` | ✅ |\n| `overflow` | `visible` &#124; `hidden` &#124; `scroll` | ✅ |\n| `flex` | `number` | ✅ |\n| `flexGrow` | `number` | ✅ |\n| `flexShrink` | `number` | ✅ |\n| `flexBasis` | `number` | ✅ |\n| `aspectRatio` | `number` | ⛔️ |\n| `zIndex` | `number` | ✅ |\n| `backfaceVisibility` | `visible` &#124; `hidden` | ⛔️ |\n| `backgroundColor` | `Color` | ✅ |\n| `borderColor` | `Color` | ✅ |\n| `borderTopColor` | `Color` | ✅ |\n| `borderRightColor` | `Color` | ✅ |\n| `borderBottomColor` | `Color` | ✅ |\n| `borderLeftColor` | `Color` | ✅ |\n| `borderRadius` | `number` &#124; `percentage` | ✅ |\n| `borderTopLeftRadius` | `number` &#124; `percentage` | ✅ |\n| `borderTopRightRadius` | `number` &#124; `percentage` | ✅ |\n| `borderBottomLeftRadius` | `number` &#124; `percentage` | ✅ |\n| `borderBottomRightRadius` | `number` &#124; `percentage` | ✅ |\n| `borderStyle` | `solid` &#124; `dotted` &#124; `dashed` | ✅ |\n| `borderWidth` | `number` &#124; `percentage` | ✅ |\n| `borderTopWidth` | `number` &#124; `percentage` | ✅ |\n| `borderRightWidth` | `number` &#124; `percentage` | ✅ |\n| `borderBottomWidth` | `number` &#124; `percentage` | ✅ |\n| `borderLeftWidth` | `number` &#124; `percentage` | ✅ |\n| `opacity` | `number` | ✅ |\n\n## Shadow Styles\n\n| property | type | supported? |\n| --- | --- | --- |\n| `shadowColor` | `Color` | ✅ |\n| `shadowOffset` | `{ width: number, height: number }` | ✅ |\n| `shadowOpacity` | `number` | ✅ |\n| `shadowRadius` | `number` &#124; `percentage` | ✅ |\n\n## Type Styles\n\n| property | type | supported? |\n| --- | --- | --- |\n| `color` | `Color` | ✅ |\n| `fontFamily` | `string` | ✅ |\n| `fontSize` | `number` | ✅ |\n| `fontStyle` | `normal` &#124; `italic` | ✅ |\n| `fontWeight` | `string` &#124; `number` | ✅ |\n| `textDecorationLine` | `none` &#124; `underline` &#124; `double` &#124; `line-through` | ✅ |\n| `textShadowOffset` | `{ width: number, height: number }` | ✅ |\n| `textShadowRadius` | `number` | ✅ |\n| `textShadowColor` | `Color` | ✅ |\n| `textTransform` | `none` &#124; `uppercase` &#124; `lowercase` | ✅ |\n| `letterSpacing` | `number` | ✅ |\n| `lineHeight` | `number` | ✅ |\n| `textAlign` | `auto` &#124; `left` &#124; `right` &#124; `center` &#124; `justify` | ✅ |\n| `writingDirection` | `auto` &#124; `ltr` &#124; `rtl` | ⛔️ |\n| `opacity` | `number` | ✅ |\n| `percentage` | `points` &#124; `percentages` | ✅ |\n\n## Styles Specific To `react-sketchapp`\n\nSome properties are Sketch specific and won't work cross-platform but give you a better control over your components.\n\n| property | type | supported? |\n| --- | --- | --- |\n| `shadowSpread` | `number` | ✅ |\n| `shadowInner` | `boolean` | ✅ |\n\n## Examples\n\nStyles can be passed to components as plain objects, or via [`StyleSheet`](/docs/API.md).\n\n```js\nimport { View, StyleSheet } from 'react-sketchapp';\n\n// inline props\n<View\n  style={{\n    backgroundColor: 'hotPink',\n    width: 300,\n  }}\n/>\n\n// plain JS object\nconst style = {\n  backgroundColor: 'hotPink',\n  width: 300,\n}\n\n<View style={style} />\n\n// StyleSheet\nconst styles = StyleSheet.create({\n  foo: {\n    backgroundColor: 'hotPink',\n    width: 300,\n  }\n})\n\n<View style={styles.foo} />\n<View style={[styles.foo, styles.bar]} />\n```\n\nYou can use variables in your styles just like a standard React application:\n\n```javascript\nconst colors = {\n  Haus: '#F3F4F4',\n  Night: '#333',\n  Sur: '#96DBE4',\n  Peach: '#EFADA0',\n  Pear: '#93DAAB',\n};\n\n<View>\n  {Object.keys(colors).map(name => (\n    <View\n      key={name}\n      style={{\n        flex: 1,\n        backgroundColor: colors[name],\n      }}\n    />\n  ))}\n</View>;\n```\n"
  },
  {
    "path": "docs/guides/universal-rendering.md",
    "content": "# Universal Rendering\n\nThe `react-sketchapp` components have been architected to provide the same metaphors, layout system & interfaces as `react-native`, so there is less switching cost between platforms. However, it is also possible to render the _same code_ across multiple platforms. We call this _Universal Rendering_.\n\nThe [`react-primitives`](https://github.com/lelandrichardson/react-primitives) project provides consistent primitive interfaces across platforms, and is the simplest way to achieve Universal Rendering.\n\n## Setup\n\nReact Primitives works out-of-the-box with `react-dom` & `react-native`, and `react-sketchapp` (when using `skpm`).\n\nInstall `react-primitives` and its peer dependencies\n\n```bash\nnpm install --save react-primitives react react-dom react-native react-sketchapp\n```\n\n## Creating your components\n\nImport base primitives from `react-primitives` rather than `react-sketchapp` / `react-native` — e.g.\n\n```diff\n/**\n * components/Row.js\n * Define your component using platform-independent primitives\n */\nimport React from 'react';\n- import { View, Text, StyleSheet } from 'react-sketchapp';\n+ import { View, Text, StyleSheet } from 'react-primitives';\n\nconst Row = props =>\n  <View>\n    <Text>{ props.title }</Text>\n    <Text>{ props.subtitle }</Text>\n  </View>\n\nexport default Row;\n```\n\n## Importing existing components\n\nIf you have a large existing React Native component library, you might enjoy using a `codemod` to automatically convert `react-native` imports to `react-primitives` — [a proof-of-concept `codemod` is provided on ASTExplorer](https://astexplorer.net/#/gist/68d1b3ae3ec7b0a088452a7d38643dc4/latest).\n\n## Rendering\n\nEach platform will require an entry point with its respective `render` / registration call - e.g:\n\n```js\n/**\n * dom-entry.js\n * Standard ReactDOM setup for the browser\n */\nimport React from 'react';\nimport { render } from 'react-dom';\nimport Row from './components/Row';\n\nrender(<Row title=\"Foo\" subtitle=\"Bar\" />, document.getElementById('root'));\n```\n\n```js\n/**\n * native-entry.js\n * Standard ReactNative setup\n */\nimport React from 'react';\nimport { AppRegistry } from 'react-native';\nimport Row from './components/Row';\n\nAppRegistry.registerComponent('Row', () => Row);\n```\n\n```js\n/**\n * sketch-entry.js\n * same setup as other examples\n */\nimport React from 'react';\nimport { render } from 'react-sketchapp';\nimport Row from './components/Row';\n\nexport default context => {\n  render(<Row title=\"Foo\" subtitle=\"Bar\" />, context.document.currentPage());\n};\n```\n\nReact Primitives only provides components that make sense on every platform, so Sketch-specific concepts like `TextStyles` and `<Artboard />` should be imported from the main `react-sketchapp` package. You can mix-and-match them as necessary - e.g.\n\n```js\n/**\n * sketch-entry.js\n * same setup as other examples\n */\nimport React from 'react';\nimport { Artboard, render } from 'react-sketchapp';\nimport Row from './components/Row'; // built with react-primitives\n\nexport default context => {\n  render(\n    <Artboard>\n      <Row title=\"Foo\" subtitle=\"Bar\" />\n    </Artboard>,\n    context.document.currentPage(),\n  );\n};\n```\n"
  },
  {
    "path": "docs/guides/using-skpm.md",
    "content": "# Using `skpm` as a build system\n\nSketch allows arbitrary plugins written in [CocoaScript](http://developer.sketchapp.com/guides/cocoascript) to run. [`skpm`](https://github.com/skpm/skpm) is a utility to create, build and manage Sketch plugins. It takes care of transforming your JavaScript into CocoaScript and makes sure the context it is running in is as close as possible to what you are used to when writing JavaScript.\n\n## Installation\n\n> Important: Node.JS > V6.x is a minimum requirement.\n\n```bash\nnpm install -g skpm\n```\n\n## Usage\n\n### Creating a new plugin\n\n```bash\nskpm create my-plugin --template=airbnb/react-sketchapp\n```\n\n> A note on templates\n>\n> The purpose of skpm templates are to provide opinionated development tooling setups so that users can get started with actual plugin code as fast as possible.\n>\n> - [`airbnb/react-sketchapp`](https://github.com/airbnb/react-sketchapp) is a simple template to get started with `react-sketchapp`\n>\n> 💁 Tip: Any Github repo with a 'template' folder can be used as a custom template: `skpm create <project-name> --template=<username>/<repository>`\n\n### Build the plugin\n\nOnce the installation is done, you can run some commands inside the project folder:\n\n```bash\nnpm run build\n```\n\nTo watch for changes:\n\n```bash\nnpm run watch\n```\n\nAdditionally, if you wish to run the plugin every time it is built:\n\n```bash\nnpm run render\n```\n\n### View the plugin's log\n\nTo view the output of your `console.log`, you have a few different options:\n\n- Using the [sketch-dev-tools](https://github.com/skpm/sketch-dev-tools)\n- Open Console.app and look for the sketch logs\n- Look at the `~/Library/Logs/com.bohemiancoding.sketch3/Plugin Output.log` file\n\nSkpm provides a convenient way to do the latter:\n\n```bash\nskpm log\n\n  -f, -F        The `-f` option causes tail to not stop when end of file is\n                reached, but rather to wait for additional data to be appended\n                to the input.                       [boolean] [default: \"false\"]\n  --number, -n  Shows `number` lines of the logs.                       [number]\n```\n\n## Custom Configuration\n\n### Babel\n\nTo customize Babel, you have two options:\n\n- You may create a [`.babelrc`](https://babeljs.io/docs/usage/babelrc) file in your project's root directory. Any settings you define here will overwrite matching config-keys within skpm preset. For example, if you pass a \"presets\" object, it will replace & reset all Babel presets that skpm defaults to.\n\n- If you'd like to modify or add to the existing Babel config, you must use a `webpack.skpm.config.js` file. Visit the [`webpack`](#webpack) section for more info.\n\n### `webpack`\n\nTo customize `webpack` create `webpack.skpm.config.js` file which exports function that will change `webpack`'s config.\n\n```js\n/**\n * Function that mutates original webpack config.\n * Supports asynchronous changes when promise is returned.\n *\n * @param {object} config - original webpack config.\n * @param {boolean} isPluginCommand - wether the config is for a plugin command or a resource\n **/\nmodule.exports = function(config, isPluginCommand) {\n  /** you can change config here **/\n};\n```\n"
  },
  {
    "path": "examples/.eslintrc",
    "content": "{\n  \"rules\": {\n    \"import/no-unresolved\": 0,\n    \"import/extensions\": 0\n  }\n}\n"
  },
  {
    "path": "examples/.gitignore",
    "content": "**/*.sketchplugin\n"
  },
  {
    "path": "examples/basic-setup/README.md",
    "content": "# Basic setup\n\n## How to use\n\nDownload the example or [clone the repo](http://github.com/airbnb/react-sketchapp):\n\n```bash\ncurl https://codeload.github.com/airbnb/react-sketchapp/tar.gz/master | tar -xz --strip=2 react-sketchapp-master/examples/basic-setup\ncd basic-setup\n```\n\nInstall the dependencies\n\n```bash\nnpm install\n```\n\nThen, open Sketch and navigate to `Plugins → react-sketchapp: Basic skpm Example`\n\nRun with live reloading in Sketch, need a new sketch doc open\n\n```bash\nnpm run render\n```\n\n## The idea behind the example\n\n[`skpm`](https://github.com/skpm/skpm) is the easiest way to build `react-sketchapp` projects - this is a minimal example of it in use.\n\n![examples-basic](https://cloud.githubusercontent.com/assets/591643/24778192/1f0684ec-1ade-11e7-866b-b11bb60ac109.png)\n"
  },
  {
    "path": "examples/basic-setup/package.json",
    "content": "{\n  \"name\": \"basic-setup\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"skpm\": {\n    \"main\": \"basic-setup.sketchplugin\",\n    \"manifest\": \"src/manifest.json\"\n  },\n  \"scripts\": {\n    \"build\": \"skpm-build\",\n    \"watch\": \"skpm-build --watch\",\n    \"render\": \"skpm-build --watch --run\",\n    \"render:once\": \"skpm-build --run\",\n    \"postinstall\": \"npm run build && skpm-link\"\n  },\n  \"author\": \"Jon Gold <jon.gold@airbnb.com>\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@skpm/builder\": \"^0.7.5\"\n  },\n  \"dependencies\": {\n    \"chroma-js\": \"^1.2.2\",\n    \"prop-types\": \"^15.5.8\",\n    \"react\": \"^16.3.2\",\n    \"react-sketchapp\": \"^3.0.0\",\n    \"react-test-renderer\": \"^16.3.2\"\n  }\n}\n"
  },
  {
    "path": "examples/basic-setup/src/manifest.json",
    "content": "{\n\t\"compatibleVersion\": 3,\n\t\"bundleVersion\": 1,\n\t\"commands\": [\n\t\t{\n\t\t\t\"name\": \"react-sketchapp: Basic Setup\",\n\t\t\t\"identifier\": \"main\",\n\t\t\t\"script\": \"./my-command.js\"\n\t\t}\n\t],\n\t\"menu\": {\n\t\t\"isRoot\": true,\n\t\t\"items\": [\n\t\t\t\"main\"\n\t\t]\n\t}\n}\n"
  },
  {
    "path": "examples/basic-setup/src/my-command.js",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { render, Artboard, Text, View } from 'react-sketchapp';\nimport chroma from 'chroma-js';\n\n// take a hex and give us a nice text color to put over it\nconst textColor = (hex) => {\n  const vsWhite = chroma.contrast(hex, 'white');\n  if (vsWhite > 4) {\n    return '#FFF';\n  }\n  return chroma(hex).darken(3).hex();\n};\n\nconst Swatch = ({ name, hex }) => (\n  <View\n    name={`Swatch ${name}`}\n    style={{\n      height: 96,\n      width: 96,\n      margin: 4,\n      backgroundColor: hex,\n      padding: 8,\n    }}\n  >\n    <Text\n      name=\"Swatch Name\"\n      style={{ color: textColor(hex), fontWeight: 'bold', fontFamily: 'Helvetica' }}\n    >\n      {name}\n    </Text>\n    <Text name=\"Swatch Hex\" style={{ color: textColor(hex) }}>\n      {hex}\n    </Text>\n  </View>\n);\n\nconst Color = {\n  hex: PropTypes.string.isRequired,\n  name: PropTypes.string.isRequired,\n};\n\nSwatch.propTypes = Color;\n\nconst Document = ({ colors }) => (\n  <Artboard\n    name=\"Swatches\"\n    style={{\n      flexDirection: 'row',\n      flexWrap: 'wrap',\n      width: (96 + 8) * 4,\n    }}\n  >\n    {Object.keys(colors).map((color) => (\n      <Swatch name={color} hex={colors[color]} key={color} />\n    ))}\n  </Artboard>\n);\n\nDocument.propTypes = {\n  colors: PropTypes.objectOf(PropTypes.string).isRequired,\n};\n\nexport default () => {\n  const colorList = {\n    Haus: '#F3F4F4',\n    Night: '#333',\n    Sur: '#96DBE4',\n    'Sur Dark': '#24828F',\n    Peach: '#EFADA0',\n    'Peach Dark': '#E37059',\n    Pear: '#93DAAB',\n    'Pear Dark': '#2E854B',\n  };\n\n  render(<Document colors={colorList} />, context.document.currentPage());\n};\n"
  },
  {
    "path": "examples/basic-setup/webpack.skpm.config.js",
    "content": "const path = require('path');\n\nmodule.exports = (config) => {\n  if (process.env.LOCAL_DEV) {\n    config.resolve = {\n      ...config.resolve,\n      alias: {\n        ...config.resolve.alias,\n        'react-sketchapp': path.resolve(__dirname, '../../'),\n      },\n    };\n  }\n};\n"
  },
  {
    "path": "examples/basic-setup-typescript/.gitignore",
    "content": "node_modules\n.ts-compiled\n"
  },
  {
    "path": "examples/basic-setup-typescript/README.md",
    "content": "# Basic setup with Typescript\n\nThis example was adapted from the [basic-setup example](../basic-setup).\n\n> **NOTE:** you may also use the typings _without_ using typescript if you editor supports it. [See here](../../docs/guides/community-provided-tooling.md).\n\n## How to use\n\nDownload the example or [clone the repo](http://github.com/airbnb/react-sketchapp):\n\n```bash\ncurl https://codeload.github.com/airbnb/react-sketchapp/tar.gz/master | tar -xz --strip=2 react-sketchapp-master/examples/basic-setup-typescript\ncd basic-setup-typescript\n```\n\nInstall the dependencies\n\n```bash\nnpm install\n```\n\nRun with live reloading in Sketch, need a new sketch doc open. This will put both skpm and the Typescript compiler in watch mode:\n\n```bash\nnpm run render\n```\n\nTo clean the `.ts-compiled` directory, you can run:\n\n```bash\nnpm run typescript:clean\n```\n\n## How the typescript works\n\nThis example compiles the typescript into javascript that can be used by `skpm`. The compiled typescript files get output into the `.ts-compiled` directory. The `manifest.json` of `skpm` then simply points to the compiled javascript. To get live re-loading working, use the typescript compiler in watch mode. Whenever you save a typescript file, the typescript compiler will output javascript to the `.ts-compiled` directory. Once `skpm` notices the javascript file in `.ts-compiled` changes, it will re-build and re-render.\n\nHere is a reference `tsconfig.json`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"es2015\",\n    \"module\": \"es2015\",\n    \"jsx\": \"react-native\",\n    \"allowJs\": true,\n    \"strict\": true,\n    \"outDir\": \"./.ts-compiled\",\n    \"rootDir\": \"./src\",\n    \"allowSyntheticDefaultImports\": true,\n    \"moduleResolution\": \"node\"\n  },\n  \"include\": [\n    \"./src/**/*\"\n  ]\n}\n```\n"
  },
  {
    "path": "examples/basic-setup-typescript/manifest.json",
    "content": "{\n\t\"compatibleVersion\": 3,\n\t\"bundleVersion\": 1,\n\t\"commands\": [\n\t\t{\n\t\t\t\"name\": \"react-sketchapp: Basic Setup with Typescript\",\n\t\t\t\"identifier\": \"main\",\n\t\t\t\"script\": \"./.ts-compiled/my-command.js\"\n\t\t}\n\t],\n\t\"menu\": {\n\t\t\"isRoot\": true,\n\t\t\"items\": [\n\t\t\t\"main\"\n\t\t]\n\t}\n}"
  },
  {
    "path": "examples/basic-setup-typescript/package.json",
    "content": "{\n  \"name\": \"basic-setup-typescript\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"skpm\": {\n    \"main\": \"basic-setup.sketchplugin\",\n    \"manifest\": \"./manifest.json\"\n  },\n  \"scripts\": {\n    \"build\": \"npm run typescript:once && skpm-build\",\n    \"watch\": \"skpm-build --watch & npm run typescript\",\n    \"render\": \"skpm-build --watch --run & npm run typescript\",\n    \"render:once\": \"npm run typescript:once && skpm-build --run\",\n    \"postinstall\": \"npm run build && skpm-link\",\n    \"typescript\": \"tsc --watch\",\n    \"typescript:once\": \"tsc\",\n    \"typescript:clean\": \"rm -rf ./.ts-compiled\"\n  },\n  \"author\": \"Jon Gold <jon.gold@airbnb.com>\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@skpm/builder\": \"^0.4.0\",\n    \"@types/chroma-js\": \"^1.3.3\",\n    \"typescript\": \"^3.7.2\"\n  },\n  \"dependencies\": {\n    \"chroma-js\": \"^1.2.2\",\n    \"prop-types\": \"^15.5.8\",\n    \"react\": \"^16.3.2\",\n    \"react-sketchapp\": \"^3.0.0\",\n    \"react-test-renderer\": \"^16.3.2\"\n  }\n}\n"
  },
  {
    "path": "examples/basic-setup-typescript/src/my-command.tsx",
    "content": "import * as React from 'react';\nimport sketch from 'sketch';\nimport { render, Artboard, Text, View } from 'react-sketchapp';\nimport chroma from 'chroma-js';\n\n// take a hex and give us a nice text color to put over it\nconst textColor = (hex: string) => {\n  const vsWhite = chroma.contrast(hex, 'white');\n  if (vsWhite > 4) {\n    return '#FFF';\n  }\n  return chroma(hex).darken(3).hex();\n};\n\ninterface SwatchProps {\n  name: string;\n  hex: string;\n}\n\nconst Swatch = ({ name, hex }: SwatchProps) => (\n  <View\n    name={`Swatch ${name}`}\n    style={{\n      height: 96,\n      width: 96,\n      margin: 4,\n      backgroundColor: hex,\n      padding: 8,\n    }}\n  >\n    <Text name=\"Swatch Name\" style={{ color: textColor(hex), fontWeight: 'bold' }}>\n      {name}\n    </Text>\n    <Text name=\"Swatch Hex\" style={{ color: textColor(hex) }}>\n      {hex}\n    </Text>\n  </View>\n);\n\ninterface DocumentProps {\n  colors: { [key: string]: string };\n}\nconst Document = ({ colors }: DocumentProps) => (\n  <Artboard\n    name=\"Swatches\"\n    style={{\n      flexDirection: 'row',\n      flexWrap: 'wrap',\n      width: (96 + 8) * 4,\n    }}\n  >\n    {Object.keys(colors).map((color) => (\n      <Swatch name={color} hex={colors[color]} key={color} />\n    ))}\n  </Artboard>\n);\n\nexport default () => {\n  const colorList = {\n    Haus: '#F3F4F4',\n    Night: '#333',\n    Sur: '#96DBE4',\n    'Sur Dark': '#24828F',\n    Peach: '#EFADA0',\n    'Peach Dark': '#E37059',\n    Pear: '#93DAAB',\n    'Pear Dark': '#2E854B',\n    'TypeScript Blue': '#007ACC',\n  };\n\n  render(<Document colors={colorList} />, sketch.getSelectedDocument().selectedPage);\n};\n"
  },
  {
    "path": "examples/basic-setup-typescript/src/types/sketch.d.ts",
    "content": "declare module 'sketch';\n"
  },
  {
    "path": "examples/basic-setup-typescript/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es2015\",\n    \"module\": \"es2015\",\n    \"jsx\": \"react-native\",\n    \"allowJs\": true,\n    \"strict\": true,\n    \"outDir\": \"./.ts-compiled\",\n    \"rootDir\": \"./src\",\n    \"allowSyntheticDefaultImports\": true,\n    \"moduleResolution\": \"node\"\n  },\n  \"include\": [\n    \"./src/**/*\"\n  ]\n}\n"
  },
  {
    "path": "examples/basic-setup-typescript/webpack.skpm.config.js",
    "content": "const path = require('path');\n\nmodule.exports = (config) => {\n  if (process.env.LOCAL_DEV) {\n    config.resolve = {\n      ...config.resolve,\n      alias: {\n        ...config.resolve.alias,\n        'react-sketchapp': path.resolve(__dirname, '../../'),\n      },\n    };\n  }\n};\n"
  },
  {
    "path": "examples/basic-svg/README.md",
    "content": "# Basic SVG example\n\n## How to use\n\nDownload the example or [clone the repo](http://github.com/airbnb/react-sketchapp):\n\n```bash\ncurl https://codeload.github.com/airbnb/react-sketchapp/tar.gz/master | tar -xz --strip=2 react-sketchapp-master/examples/basic-svg\ncd basic-svg\n```\n\nInstall the dependencies\n\n```bash\nnpm install\n```\n\nRun with live reloading in Sketch, need a new sketch doc open\n\n```bash\nnpm run render\n```\n\nOr, to install as a Sketch plugin:\n\n```bash\nnpm run build\nnpm run link-plugin\n```\n\nThen, open Sketch and navigate to `Plugins → react-sketchapp: Basic SVG Example`\n\n## The idea behind the example\n\n[`skpm`](https://github.com/sketch-pm/skpm) is the easiest way to build `react-sketchapp` projects - this is a minimal example of it in use.\n\n![examples-basic](https://cloud.githubusercontent.com/assets/591643/24778192/1f0684ec-1ade-11e7-866b-b11bb60ac109.png)\n"
  },
  {
    "path": "examples/basic-svg/package.json",
    "content": "{\n  \"name\": \"basic-svg\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"skpm\": {\n    \"main\": \"basic-svg.sketchplugin\",\n    \"manifest\": \"src/manifest.json\"\n  },\n  \"scripts\": {\n    \"build\": \"skpm-build\",\n    \"watch\": \"skpm-build --watch\",\n    \"render\": \"skpm-build --watch --run\",\n    \"render:once\": \"skpm-build --run\",\n    \"postinstall\": \"npm run build && skpm-link\"\n  },\n  \"author\": \"Jon Gold <jon.gold@airbnb.com>\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@skpm/builder\": \"^0.7.5\"\n  },\n  \"dependencies\": {\n    \"prop-types\": \"^15.5.8\",\n    \"react\": \"^16.3.2\",\n    \"react-sketchapp\": \"^3.0.0\",\n    \"react-test-renderer\": \"^16.3.2\"\n  }\n}\n"
  },
  {
    "path": "examples/basic-svg/src/manifest.json",
    "content": "{\n\t\"compatibleVersion\": 3,\n\t\"bundleVersion\": 1,\n\t\"commands\": [\n\t\t{\n\t\t\t\"name\": \"react-sketchapp: Basic SVG\",\n\t\t\t\"identifier\": \"main\",\n\t\t\t\"script\": \"./my-command.js\"\n\t\t}\n\t],\n\t\"menu\": {\n\t\t\"isRoot\": true,\n\t\t\"items\": [\n\t\t\t\"main\"\n\t\t]\n\t}\n}\n"
  },
  {
    "path": "examples/basic-svg/src/my-command.js",
    "content": "import * as React from 'react';\nimport { render, Artboard, Svg } from 'react-sketchapp';\n\nconst Document = () => (\n  <Artboard\n    name=\"Sketch Logo\"\n    style={{\n      width: 494,\n      height: 447,\n    }}\n  >\n    <Svg xmlns=\"http://www.w3.org/2000/svg\" width=\"494\" height=\"447\" viewBox=\"0 0 494 447\">\n      <Svg.G fill=\"none\" fillRule=\"evenodd\">\n        <Svg.Path fill=\"#FFAE00\" d=\"M247 447L0 160 107 15 247 0l140 15 107 145\" />\n        <Svg.Path fill=\"#EC6C00\" d=\"M247 447L0 160h494\" />\n        <Svg.Path fill=\"#FFAE00\" d=\"M247 447L100 160h294\" />\n        <Svg.Path fill=\"#FFEFB4\" d=\"M247 0L100 160h294\" />\n        <Svg.Path fill=\"#FFAE00\" d=\"M107 15L52 88 0 160h101M387 15l55 73 52 72H393\" />\n        <Svg.Path fill=\"#FED305\" d=\"M107 15l-7 145L247 0m140 15l7 145L247 0\" />\n      </Svg.G>\n    </Svg>\n  </Artboard>\n);\n\nexport default () => {\n  render(<Document />, context.document.currentPage());\n};\n"
  },
  {
    "path": "examples/basic-svg/webpack.skpm.config.js",
    "content": "const path = require('path');\n\nmodule.exports = (config) => {\n  if (process.env.LOCAL_DEV) {\n    config.resolve = {\n      ...config.resolve,\n      alias: {\n        ...config.resolve.alias,\n        'react-sketchapp': path.resolve(__dirname, '../../'),\n      },\n    };\n  }\n};\n"
  },
  {
    "path": "examples/colors/README.md",
    "content": "# Generative Colors w/ chroma-js\n\n## How to use\n\nDownload the example or [clone the repo](http://github.com/airbnb/react-sketchapp):\n\n```bash\ncurl https://codeload.github.com/airbnb/react-sketchapp/tar.gz/master | tar -xz --strip=2 react-sketchapp-master/examples/colors\ncd colors\n```\n\nInstall the dependencies\n\n```bash\nnpm install\n```\n\nThen, open Sketch and navigate to `Plugins → react-sketchapp: Generative Colors`\n\nRun with live reloading in Sketch, need a new sketch doc open\n\n```bash\nnpm run render\n```\n\n## The idea behind the example\n\nCalculating color scales is pretty tricky in Sketch - have fun with it!\n\n![examples-colors](https://cloud.githubusercontent.com/assets/591643/24778153/efc76cdc-1add-11e7-93dd-0351f8f428c0.png)\n"
  },
  {
    "path": "examples/colors/package.json",
    "content": "{\n  \"name\": \"colors\",\n  \"version\": \"1.0.0\",\n  \"private\": true,\n  \"skpm\": {\n    \"main\": \"colors.sketchplugin\",\n    \"manifest\": \"src/manifest.json\"\n  },\n  \"scripts\": {\n    \"build\": \"skpm-build\",\n    \"watch\": \"skpm-build --watch\",\n    \"render\": \"skpm-build --watch --run\",\n    \"render:once\": \"skpm-build --run\",\n    \"postinstall\": \"npm run build && skpm-link\"\n  },\n  \"author\": \"Jon Gold <jon.gold@airbnb.com>\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"chroma-js\": \"^1.2.2\",\n    \"prop-types\": \"^15.5.8\",\n    \"ramda\": \"^0.23.0\",\n    \"react\": \"^16.3.2\",\n    \"react-sketchapp\": \"^3.0.0\",\n    \"react-test-renderer\": \"^16.3.2\",\n    \"webpack-shell-plugin\": \"^0.5.0\"\n  },\n  \"devDependencies\": {\n    \"@skpm/builder\": \"^0.4.0\"\n  }\n}\n"
  },
  {
    "path": "examples/colors/src/main.js",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { render, StyleSheet, View } from 'react-sketchapp';\nimport chroma from 'chroma-js';\nimport { times } from 'ramda';\n\nconst styles = StyleSheet.create({\n  container: {\n    width: 480,\n    height: 480,\n    flexDirection: 'row',\n    flexWrap: 'wrap',\n    alignItems: 'center',\n  },\n});\n\nconst Document = ({ colors, steps }) => {\n  const color = chroma.scale(colors);\n\n  return (\n    <View style={styles.container}>\n      {times((i) => color(i / steps).hex(), steps).map((val, i) => (\n        <View\n          name={val}\n          key={val}\n          style={{\n            backgroundColor: val,\n            margin: 2,\n            // prettier-ignore\n            height: 96 - (2 * i),\n            // prettier-ignore\n            width: 96 - (2 * i),\n            borderRadius: 2 * i,\n          }}\n        />\n      ))}\n    </View>\n  );\n};\nDocument.propTypes = {\n  colors: PropTypes.arrayOf(PropTypes.string),\n  steps: PropTypes.number,\n};\n\nexport default () => {\n  render(\n    <Document colors={['#01FFD8', '#C137E3', '#8702ED']} steps={50} />,\n    context.document.currentPage(),\n  );\n};\n"
  },
  {
    "path": "examples/colors/src/manifest.json",
    "content": "{\n  \"name\": \"colors\",\n  \"author\": \"Jon Gold\",\n  \"version\": 0.1,\n  \"compatibleVersion\": 1,\n  \"bundleVersion\": 1,\n  \"disableCocoaScriptPreprocessor\": true,\n  \"commands\": [\n    {\n      \"name\": \"react-sketchapp: Generative Colors\",\n      \"identifier\": \"main\",\n      \"script\": \"main.js\"\n    }\n  ],\n  \"menu\": {\n    \"isRoot\": true,\n    \"items\": [\n      \"main\"\n    ]\n  }\n}\n"
  },
  {
    "path": "examples/colors/webpack.skpm.config.js",
    "content": "const path = require('path');\n\nmodule.exports = (config) => {\n  if (process.env.LOCAL_DEV) {\n    config.resolve = {\n      ...config.resolve,\n      alias: {\n        ...config.resolve.alias,\n        'react-sketchapp': path.resolve(__dirname, '../../'),\n      },\n    };\n  }\n};\n"
  },
  {
    "path": "examples/emotion/package.json",
    "content": "{\n  \"name\": \"emotion-example\",\n  \"version\": \"1.0.0\",\n  \"skpm\": {\n    \"main\": \"emotion.sketchplugin\",\n    \"manifest\": \"src/manifest.json\"\n  },\n  \"scripts\": {\n    \"build\": \"skpm-build\",\n    \"watch\": \"skpm-build --watch\",\n    \"render\": \"skpm-build --watch --run\",\n    \"render:once\": \"skpm-build --run\",\n    \"postinstall\": \"npm run build && skpm-link\"\n  },\n  \"author\": \"Nitin Tulswani <tulswani19@gmail.com>\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@skpm/builder\": \"^0.4.3\"\n  },\n  \"dependencies\": {\n    \"emotion-primitives\": \"^1.0.0-beta.6\",\n    \"react\": \"^16.4.1\",\n    \"react-primitives\": \"^0.6.0\",\n    \"react-sketchapp\": \"^3.0.0\",\n    \"react-test-renderer\": \"^16.3.2\"\n  }\n}\n"
  },
  {
    "path": "examples/emotion/src/manifest.json",
    "content": "{\n\t\"compatibleVersion\": 3,\n\t\"bundleVersion\": 1,\n\t\"commands\": [\n\t\t{\n\t\t\t\"name\": \"react-sketchapp: emotion\",\n\t\t\t\"identifier\": \"main\",\n\t\t\t\"script\": \"./my-command.js\"\n\t\t}\n\t],\n\t\"menu\": {\n\t\t\"isRoot\": true,\n\t\t\"items\": [\"main\"]\n\t}\n}\n"
  },
  {
    "path": "examples/emotion/src/my-command.js",
    "content": "import React from 'react';\nimport emotion from 'emotion-primitives';\nimport { render } from 'react-sketchapp';\n\nconst Container = emotion.View`\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  margin: 50px;\n  border: 5px solid red;\n  background-color: ${(props) => props.theme.backgroundColor}\n`;\n\nconst Description = emotion.Text`\n  color: hotpink;\n`;\n\nconst Image = emotion.Image`\n  padding: 40px;\n`;\n\nconst emotionLogo = 'https://avatars3.githubusercontent.com/u/31557565?s=400&v=4';\n\nclass App extends React.Component {\n  render() {\n    return (\n      <Container borderRadius=\"10px\">\n        <Description fontSize={45} fontWeight=\"bold\">\n          Emotion Primitives\n        </Description>\n        <Image\n          source={{\n            uri: emotionLogo,\n            height: 150,\n            width: 150,\n          }}\n        />\n      </Container>\n    );\n  }\n}\n\nexport default () => {\n  render(<App />, context.document.currentPage());\n};\n"
  },
  {
    "path": "examples/emotion/webpack.skpm.config.js",
    "content": "const path = require('path');\n\nmodule.exports = (config) => {\n  if (process.env.LOCAL_DEV) {\n    config.resolve = {\n      ...config.resolve,\n      alias: {\n        ...config.resolve.alias,\n        'react-sketchapp': path.resolve(__dirname, '../../'),\n      },\n    };\n  }\n};\n"
  },
  {
    "path": "examples/form-validation/README.md",
    "content": "# Form Validation\n\n## How to use\n\nDownload the example or [clone the repo](http://github.com/airbnb/react-sketchapp):\n\n```bash\ncurl https://codeload.github.com/airbnb/react-sketchapp/tar.gz/master | tar -xz --strip=2 react-sketchapp-master/examples/form-validation\ncd form-validation\n```\n\nInstall the dependencies\n\n```bash\nnpm install\n```\n\nThen, open Sketch and navigate to `Plugins → react-sketchapp: Form Validation`\n\nRun with live reloading in Sketch\n\n```bash\nnpm run render\n```\n\n## The idea behind the example\n\n`react-sketchapp` makes it simple to render all potential states of a web component to sketch.\n\n![examples-form-validation](https://cloud.githubusercontent.com/assets/1606253/25585002/5cff9264-2e90-11e7-80dc-101f10ecad6d.png)\n"
  },
  {
    "path": "examples/form-validation/package.json",
    "content": "{\n  \"name\": \"form-validation\",\n  \"version\": \"1.0.0\",\n  \"private\": true,\n  \"skpm\": {\n    \"main\": \"form-validation.sketchplugin\",\n    \"manifest\": \"src/manifest.json\"\n  },\n  \"scripts\": {\n    \"build\": \"skpm-build\",\n    \"watch\": \"skpm-build --watch\",\n    \"render\": \"skpm-build --watch --run\",\n    \"render:once\": \"skpm-build --run\",\n    \"postinstall\": \"npm run build && skpm-link\",\n    \"web\": \"react run src/web.js\"\n  },\n  \"author\": \"Lloyd Wheeler <lloyd@lloydwheeler.co.uk>\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"prop-types\": \"^15.5.8\",\n    \"react\": \"^16.3.2\",\n    \"react-dom\": \"^16.3.2\",\n    \"react-native\": \"^0.42.3\",\n    \"react-primitives\": \"^0.6.0\",\n    \"react-sketchapp\": \"^3.0.0\",\n    \"react-test-renderer\": \"^16.3.2\"\n  },\n  \"devDependencies\": {\n    \"extract-text-webpack-plugin\": \"^2.1.0\",\n    \"nwb\": \"^0.15.6\",\n    \"@skpm/builder\": \"^0.4.0\"\n  }\n}\n"
  },
  {
    "path": "examples/form-validation/src/components/Button.js",
    "content": "import * as React from 'react';\nimport { Text, View } from 'react-primitives';\nimport { spacing, colors, fontFamily } from '../designSystem';\n\nconst buttonStyle = {\n  borderRadius: 3,\n  boxSizing: 'border-box',\n  color: colors.White,\n  cursor: 'pointer',\n  padding: spacing.Medium,\n  width: 300,\n};\n\nconst textStyle = {\n  color: colors.White,\n  fontFamily,\n  fontWeight: 'bold',\n  textAlign: 'center',\n};\n\nconst Button = ({ label, backgroundColor }) => (\n  <View style={{ ...buttonStyle, backgroundColor }}>\n    <Text style={{ ...textStyle }}>{label}</Text>\n  </View>\n);\n\nexport default Button;\n"
  },
  {
    "path": "examples/form-validation/src/components/Register.js",
    "content": "import * as React from 'react';\nimport { View, Text, StyleSheet } from 'react-primitives';\nimport { spacing, colors, typeRamp, fontFamily } from '../designSystem';\nimport TextBox from './TextBox';\nimport StrengthMeter from './StrengthMeter';\nimport Button from './Button';\n\nconst styles = StyleSheet.create({\n  register: {\n    backgroundColor: colors.LightGrey,\n    padding: spacing.Large,\n    boxSizing: 'border-box',\n  },\n  heading: {\n    color: colors.Purple,\n    fontSize: typeRamp.Medium,\n    fontFamily,\n    fontWeight: 'bold',\n    textAlign: 'center',\n    marginBottom: spacing.Medium,\n    width: 300,\n  },\n});\n\nconst Register = ({ session }) => (\n  <View style={styles.register}>\n    <Text style={styles.heading}>Register an Account</Text>\n    <TextBox label=\"Email\" value={session.email} type=\"email\" />\n    <TextBox label=\"Password\" value={session.password} type=\"password\">\n      <StrengthMeter password={session.password} />\n    </TextBox>\n    <Button label=\"Register\" backgroundColor={colors.Purple} />\n  </View>\n);\n\nRegister.defaultProps = {\n  session: {\n    email: '',\n    password: '',\n  },\n};\n\nexport default Register;\n"
  },
  {
    "path": "examples/form-validation/src/components/Space.js",
    "content": "import * as React from 'react';\nimport { View } from 'react-primitives';\n\nconst Space = ({ h, v, children }) => (\n  <View\n    style={{\n      paddingHorizontal: h,\n      paddingVertical: v,\n    }}\n  >\n    {children}\n  </View>\n);\n\nexport default Space;\n"
  },
  {
    "path": "examples/form-validation/src/components/StrengthMeter.js",
    "content": "import * as React from 'react';\nimport { View, Text } from 'react-primitives';\nimport { colors, fontFamily, spacing, typeRamp } from '../designSystem';\n\nconst strengths = {\n  short: {\n    width: 75,\n    label: 'Too short',\n    backgroundColor: colors.Rose,\n  },\n  fair: {\n    width: 150,\n    label: 'Fair',\n    backgroundColor: colors.Yellow,\n  },\n  good: {\n    width: 225,\n    label: 'Good',\n    backgroundColor: colors.Yellow,\n  },\n  strong: {\n    width: 300,\n    label: 'Strong',\n    backgroundColor: colors.Green,\n  },\n};\n\nconst styles = {\n  meter: {\n    boxSizing: 'border-box',\n    height: 5,\n    width: 300,\n    backgroundColor: '#ddd',\n    marginTop: spacing.Medium,\n    marginBottom: spacing.Large,\n    borderRadius: 5,\n  },\n  innerMeter: {\n    boxSizing: 'border-box',\n    height: 5,\n    borderRadius: 5,\n  },\n  meterLabel: {\n    fontFamily,\n    textAlign: 'right',\n    width: 300,\n    fontSize: typeRamp.Small,\n    marginTop: 5,\n  },\n};\n\nconst passwordStrength = (password) => {\n  // Faux password checking\n  if (password.length <= 6) {\n    return 'short';\n  }\n  if (password.length <= 9) {\n    return 'fair';\n  }\n  if (password.length <= 12) {\n    return 'good';\n  }\n\n  return 'strong';\n};\n\nconst StrengthMeter = ({ password }) => (\n  <View>\n    {password.length > 0 && (\n      <View style={styles.meter}>\n        <View\n          style={{\n            ...styles.innerMeter,\n            width: strengths[passwordStrength(password)].width,\n            backgroundColor: strengths[passwordStrength(password)].backgroundColor,\n          }}\n        />\n        <Text\n          style={{\n            ...styles.meterLabel,\n            color: strengths[passwordStrength(password)].backgroundColor,\n          }}\n        >\n          {strengths[passwordStrength(password)].label}\n        </Text>\n      </View>\n    )}\n  </View>\n);\n\nexport default StrengthMeter;\n"
  },
  {
    "path": "examples/form-validation/src/components/TextBox/index.js",
    "content": "import React, { Component } from 'react';\nimport styles from './style';\n\nclass TextBox extends Component {\n  constructor(props) {\n    super(props);\n\n    this.handleChange = this.handleChange.bind(this);\n\n    this.state = {\n      value: this.props.value,\n    };\n  }\n\n  handleChange(event) {\n    this.setState({ value: event.target.value });\n  }\n\n  render() {\n    return (\n      <div style={styles.formElement}>\n        <label style={styles.label} htmlFor={this.props.type}>\n          {this.props.label}\n        </label>\n        <input\n          id={this.props.type}\n          style={{ ...styles.textbox, lineHeight: '100%' }}\n          type={this.props.type}\n          value={this.state.value}\n          onChange={this.handleChange}\n        />\n        {this.props.children &&\n          React.cloneElement(this.props.children, {\n            password: this.state.value,\n          })}\n      </div>\n    );\n  }\n}\n\nexport default TextBox;\n"
  },
  {
    "path": "examples/form-validation/src/components/TextBox/index.sketch.js",
    "content": "import * as React from 'react';\nimport { View, Text } from 'react-primitives';\nimport styles from './style';\n\ntype Props = {\n  label: string,\n  value: string,\n  children?: React$Element<any>,\n};\n\nconst TextBox = ({ label, value, children }: Props) => (\n  <View style={styles.formElement}>\n    <Text style={styles.label}>{label}</Text>\n    <View style={styles.textbox}>\n      <Text>{value}</Text>\n    </View>\n    {children}\n  </View>\n);\n\nexport default TextBox;\n"
  },
  {
    "path": "examples/form-validation/src/components/TextBox/style.js",
    "content": "import { colors, spacing, fontFamily, typeRamp } from '../../designSystem';\n\nexport default {\n  formElement: {\n    marginBottom: spacing.Medium,\n  },\n  label: {\n    display: 'block',\n    fontFamily,\n    marginBottom: spacing.Small,\n    fontSize: typeRamp.Medium - 2,\n  },\n  textbox: {\n    boxSizing: 'border-box',\n    borderWidth: 1,\n    borderStyle: 'solid',\n    borderColor: colors.Grey,\n    backgroundColor: colors.White,\n    fontFamily,\n    fontSize: typeRamp.Medium,\n    lineHeight: typeRamp.Medium,\n    padding: spacing.Medium,\n    width: 300,\n  },\n};\n"
  },
  {
    "path": "examples/form-validation/src/data.js",
    "content": "export default [\n  {\n    email: 'john.hornsby@example.com',\n    password: '',\n  },\n  {\n    email: 'john.hornsby@example.com',\n    password: 'hello',\n  },\n  {\n    email: 'john.hornsby@example.com',\n    password: '!H3ll0!',\n  },\n  {\n    email: 'john.hornsby@example.com',\n    password: 'IL0v3ToasT!',\n  },\n  {\n    email: 'john.hornsby@example.com',\n    password: 'IRea11yL0v3ToasT!',\n  },\n];\n"
  },
  {
    "path": "examples/form-validation/src/designSystem.js",
    "content": "export const colors = {\n  Purple: '#5700A2',\n  Yellow: '#BB9A05',\n  Orange: '#fd6134',\n  Rose: '#ff4289',\n  Green: '#005b4c',\n  Black: '#222223',\n  LightGrey: '#eeeeee',\n  Grey: '#cccccc',\n  White: '#ffffff',\n};\n\nexport const spacing = {\n  xSmall: 4,\n  Small: 8,\n  Medium: 16,\n  Large: 32,\n  xLarge: 64,\n};\n\nexport const typeRamp = {\n  xSmall: 7,\n  Small: 12,\n  Medium: 16,\n  Large: 24,\n  xLarge: 36,\n};\n\nexport const typography = {\n  Heading: {\n    fontSize: typeRamp.Large,\n    textAlign: 'center',\n    marginBottom: spacing.Large,\n  },\n};\n\nexport const fontFamily = 'Helvetica';\n\nexport default {\n  colors,\n  spacing,\n  typeRamp,\n  typography,\n  fontFamily,\n};\n"
  },
  {
    "path": "examples/form-validation/src/main.js",
    "content": "import * as React from 'react';\nimport { render, View } from 'react-sketchapp';\nimport { Text } from 'react-primitives';\nimport { typography, spacing } from './designSystem';\nimport DATA from './data';\nimport Register from './components/Register';\nimport Space from './components/Space';\n\nconst Page = ({ sessions }) => (\n  <View>\n    <Text style={typography.Heading}>Form Validation w/ DOM elements and React Primitives</Text>\n    <View\n      style={{\n        flexDirection: 'row',\n        flexWrap: 'wrap',\n      }}\n    >\n      {sessions.map((session) => (\n        <Space key={session.password} h={spacing.Large} v={spacing.Large}>\n          <Register session={session} />\n        </Space>\n      ))}\n    </View>\n  </View>\n);\n\nexport default () => {\n  render(<Page sessions={DATA} />, context.document.currentPage());\n};\n"
  },
  {
    "path": "examples/form-validation/src/manifest.json",
    "content": "{\n  \"compatibleVersion\": 1,\n  \"bundleVersion\": 1,\n  \"commands\": [\n    {\n      \"name\": \"react-sketchapp: Form Validation\",\n      \"identifier\": \"main\",\n      \"script\": \"./main.js\"\n    }\n  ],\n  \"menu\": {\n    \"isRoot\": true,\n    \"items\": [\n      \"main\"\n    ]\n  }\n}\n"
  },
  {
    "path": "examples/form-validation/src/web.js",
    "content": "import * as React from 'react';\nimport { typography, fontFamily } from './designSystem';\nimport Register from './components/Register';\n\nconst styles = {\n  containerStyle: {\n    width: 364,\n    marginLeft: 'auto',\n    marginRight: 'auto',\n  },\n};\n\nexport default () => (\n  <div>\n    <div style={styles.containerStyle}>\n      <h1\n        style={{\n          ...typography.Heading,\n          fontFamily,\n        }}\n      >\n        <span>Form Validation w/ DOM elements and React Primitives. Type a password! </span>\n        <span role=\"img\" aria-label=\"icon\">\n          👀\n        </span>\n      </h1>\n      <Register />\n    </div>\n  </div>\n);\n"
  },
  {
    "path": "examples/form-validation/webpack.skpm.config.js",
    "content": "const path = require('path');\n\nmodule.exports = (config) => {\n  if (process.env.LOCAL_DEV) {\n    config.resolve = {\n      ...config.resolve,\n      alias: {\n        ...config.resolve.alias,\n        'react-sketchapp': path.resolve(__dirname, '../../'),\n      },\n    };\n  }\n};\n"
  },
  {
    "path": "examples/foursquare-maps/.eslintrc",
    "content": "{\n  \"env\": {\n    \"browser\": true,\n  }\n}\n"
  },
  {
    "path": "examples/foursquare-maps/README.md",
    "content": "# Foursquare + Google Maps\n\n## How to use\n\nDownload the example or [clone the repo](http://github.com/airbnb/react-sketchapp):\n\n```bash\ncurl https://codeload.github.com/airbnb/react-sketchapp/tar.gz/master | tar -xz --strip=2 react-sketchapp-master/examples/foursquare-maps\ncd foursquare-maps\n```\n\nInstall the dependencies\n\n```bash\nnpm install\n```\n\nThen, open Sketch and navigate to `Plugins → react-sketchapp: Foursquare + Google Maps`\n\n### Run it in Sketch\n\nRun with live reloading in Sketch\n\n```bash\nnpm run render\n```\n\n### Run it in your browser\n\n```bash\nnpm run web\n```\n\nOpen a browser to `http://localhost:3000`\n\n## The idea behind the example\n\nCreating maps with live data into Sketch is notoriously difficult — until now ;)\n\nThis example is created with `react-primitives` and renders simultaneously to Sketch & Web — maps are provided by [react-primitives-google-static-map](https://www.npmjs.com/package/react-primitives-google-static-map).\n\n![foursquare-maps](https://cloud.githubusercontent.com/assets/591643/25052095/f666928e-2104-11e7-805c-a3c73ffcabcb.png)\n"
  },
  {
    "path": "examples/foursquare-maps/package.json",
    "content": "{\n  \"name\": \"foursquare-maps\",\n  \"version\": \"1.0.0\",\n  \"private\": true,\n  \"skpm\": {\n    \"main\": \"foursquare-maps.sketchplugin\",\n    \"manifest\": \"src/manifest.json\"\n  },\n  \"scripts\": {\n    \"build\": \"skpm-build\",\n    \"watch\": \"skpm-build --watch\",\n    \"render\": \"skpm-build --watch --run\",\n    \"render:once\": \"skpm-build --run\",\n    \"web\": \"react run src/web.js\",\n    \"postinstall\": \"npm run build && skpm-link\"\n  },\n  \"author\": \"Jon Gold <jon.gold@airbnb.com>\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"jquery-param\": \"^0.2.0\",\n    \"nwb\": \"^0.15.6\",\n    \"prop-types\": \"^15.5.8\",\n    \"react\": \"^16.3.2\",\n    \"react-dom\": \"^16.3.2\",\n    \"react-native\": \"^0.42.3\",\n    \"react-primitives\": \"^0.6.0\",\n    \"react-primitives-google-static-map\": \"^1.0.1\",\n    \"react-sketchapp\": \"^3.0.0\",\n    \"react-test-renderer\": \"^16.3.2\"\n  },\n  \"devDependencies\": {\n    \"@skpm/builder\": \"^0.4.0\"\n  }\n}\n"
  },
  {
    "path": "examples/foursquare-maps/src/App.js",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport Map from 'react-primitives-google-static-map';\nimport { StyleSheet, Text, View } from 'react-primitives';\n\nconst styles = StyleSheet.create({\n  container: {\n    width: 375,\n    height: 667,\n    backgroundColor: '#fefefe',\n    borderWidth: 2,\n    borderColor: '#dfba69',\n    borderRadius: 4,\n    overflowY: 'scroll',\n  },\n  text: {\n    fontFamily: 'Helvetica',\n    fontSize: 24,\n    lineHeight: 24,\n    color: '#dfba69',\n    textAlign: 'center',\n  },\n  rowWrapper: {\n    padding: 16,\n    backgroundColor: '#FFF',\n    borderBottomWidth: 2,\n    borderBottomColor: '#dfba69',\n  },\n  rowTitle: {\n    color: '#dfba69',\n    fontSize: 18,\n    // lineHeight: 27,\n    fontWeight: 'bold',\n    fontFamily: 'GT America',\n  },\n  rowSubtitle: {\n    color: '#dfba69',\n    fontSize: 14,\n    // lineHeight: 18,\n    fontFamily: 'GT America',\n  },\n});\n\nconst LatLong = PropTypes.shape({\n  latitude: PropTypes.string,\n  longitude: PropTypes.string,\n});\n\nconst Venue = {\n  name: PropTypes.string,\n  location: PropTypes.shape({\n    address: PropTypes.string,\n  }),\n};\n\nconst Row = ({ name, location }) => (\n  <View style={styles.rowWrapper} name={name}>\n    <Text style={styles.rowTitle}>{name}</Text>\n    <Text style={styles.rowSubtitle}>{location.address}</Text>\n  </View>\n);\n\nRow.propTypes = Venue;\n\nconst App = ({ center, venues }) => {\n  const pins = venues.map((v) => ({\n    latitude: v.location.lat,\n    longitude: v.location.lng,\n  }));\n  return (\n    <View style={styles.container} name=\"Wrapper\">\n      <Map\n        {...center}\n        zoom={12}\n        scale={1}\n        hasCenterMarker={false}\n        format=\"png\"\n        size={{\n          width: 371,\n          height: 200,\n        }}\n        markers={pins}\n      />\n      <View name=\"ListView\">\n        {venues.map((v) => (\n          <Row key={v.id} {...v} />\n        ))}\n      </View>\n    </View>\n  );\n};\n\nApp.propTypes = {\n  center: LatLong,\n  venues: PropTypes.arrayOf(PropTypes.shape(Venue)),\n};\n\nexport default App;\n"
  },
  {
    "path": "examples/foursquare-maps/src/getVenues.js",
    "content": "import param from 'jquery-param';\n\nexport default () => {\n  const query = 'burger';\n  const latitude = '37.773972';\n  const longitude = '-122.431297';\n\n  const params = param({\n    v: '20161016',\n    ll: [latitude, longitude].join(','),\n    query,\n    limit: 15,\n    intent: 'checkin',\n    client_id: 'BCUJZ2MSKUWJC2Q5HVIYZLHRWGFJ2OFPKPLBP1NOBNR3VW5R',\n    client_secret: 'Q10HUP5APBQOYNTPABSH4CSKRGEAI2CXIYULYGG0EZYUUWUZ',\n  });\n\n  return fetch(`https://api.foursquare.com/v2/venues/search?${params}`)\n    .then((res) => res.json())\n    .then((data) => ({\n      venues: data.response.venues,\n      latitude,\n      longitude,\n      query,\n    }));\n};\n"
  },
  {
    "path": "examples/foursquare-maps/src/main.js",
    "content": "import * as React from 'react';\nimport { Artboard, render } from 'react-sketchapp';\nimport App from './App';\nimport getVenues from './getVenues';\n\nexport default () => {\n  getVenues().then(({ venues, latitude, longitude }) => {\n    render(\n      <Artboard>\n        <App venues={venues} center={{ latitude, longitude }} />\n      </Artboard>,\n      context.document.currentPage(),\n    );\n  });\n};\n"
  },
  {
    "path": "examples/foursquare-maps/src/manifest.json",
    "content": "{\n  \"compatibleVersion\": 1,\n  \"bundleVersion\": 1,\n  \"commands\": [\n    {\n      \"name\": \"react-sketchapp: Foursquare + Google Maps\",\n      \"identifier\": \"main\",\n      \"script\": \"./main.js\"\n    }\n  ],\n  \"menu\": {\n    \"isRoot\": true,\n    \"items\": [\n      \"main\"\n    ]\n  }\n}\n"
  },
  {
    "path": "examples/foursquare-maps/src/web.js",
    "content": "import * as React from 'react';\nimport { render } from 'react-dom';\nimport App from './App';\nimport getVenues from './getVenues';\n\ngetVenues().then(({ venues, latitude, longitude }) => {\n  render(<App venues={venues} center={{ latitude, longitude }} />, document.getElementById('app'));\n});\n"
  },
  {
    "path": "examples/foursquare-maps/webpack.skpm.config.js",
    "content": "const path = require('path');\n\nmodule.exports = (config) => {\n  if (process.env.LOCAL_DEV) {\n    config.resolve = {\n      ...config.resolve,\n      alias: {\n        ...config.resolve.alias,\n        'react-sketchapp': path.resolve(__dirname, '../../'),\n      },\n    };\n  }\n};\n"
  },
  {
    "path": "examples/glamorous/README.md",
    "content": "# glamorous 💄\n\n## How to use\n\nDownload the example or [clone the repo](http://github.com/airbnb/react-sketchapp):\n\n```bash\ncurl https://codeload.github.com/airbnb/react-sketchapp/tar.gz/master | tar -xz --strip=2 react-sketchapp-master/examples/glamorous\ncd glamorous\n```\n\nInstall the dependencies\n\n```bash\nnpm install\n```\n\nThen, open Sketch and navigate to `Plugins → react-sketchapp: glamorous`\n\n### Run it in Sketch\n\nRun with live reloading in Sketch\n\n```bash\nnpm run render\n```\n"
  },
  {
    "path": "examples/glamorous/package.json",
    "content": "{\n  \"name\": \"glamorous-example\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"skpm\": {\n    \"main\": \"glamorous.sketchplugin\",\n    \"manifest\": \"src/manifest.json\"\n  },\n  \"scripts\": {\n    \"build\": \"skpm-build\",\n    \"watch\": \"skpm-build --watch\",\n    \"render\": \"skpm-build --watch --run\",\n    \"render:once\": \"skpm-build --run\",\n    \"postinstall\": \"npm run build && skpm-link\"\n  },\n  \"author\": \"Nitin Tulswani <tulswani19@gmail.com>\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@skpm/builder\": \"^0.4.0\"\n  },\n  \"dependencies\": {\n    \"chroma-js\": \"^1.3.4\",\n    \"glamorous-primitives\": \"^2.1.0\",\n    \"react\": \"^16.3.2\",\n    \"react-sketchapp\": \"^3.0.0\",\n    \"react-test-renderer\": \"^16.3.2\"\n  }\n}\n"
  },
  {
    "path": "examples/glamorous/src/manifest.json",
    "content": "{\n\t\"compatibleVersion\": 3,\n\t\"bundleVersion\": 1,\n\t\"commands\": [\n\t\t{\n\t\t\t\"name\": \"react-sketchapp: glamorous\",\n\t\t\t\"identifier\": \"main\",\n\t\t\t\"script\": \"./my-command.js\"\n\t\t}\n\t],\n\t\"menu\": {\n\t\t\"isRoot\": true,\n\t\t\"items\": [\n\t\t\t\"main\"\n\t\t]\n\t}\n}\n"
  },
  {
    "path": "examples/glamorous/src/my-command.js",
    "content": "import * as React from 'react';\nimport glamorous from 'glamorous-primitives';\nimport { render } from 'react-sketchapp';\n\nconst Container = glamorous.view({\n  display: 'flex',\n  justifyContent: 'center',\n  alignItems: 'center',\n});\n\nconst Image = glamorous.image({\n  width: 400,\n  height: 400,\n});\n\nconst Description = glamorous.text({\n  fontSize: 35,\n  padding: 40,\n  color: '#a4a4c1',\n});\n\nclass App extends React.Component {\n  render() {\n    return (\n      <Container>\n        <Image\n          source={{\n            uri: 'https://github.com/paypal/glamorous/raw/master/other/logo/full.png',\n          }}\n        />\n        <Description>Maintainable CSS with React</Description>\n      </Container>\n    );\n  }\n}\n\nexport default () => {\n  render(<App />, context.document.currentPage());\n};\n"
  },
  {
    "path": "examples/glamorous/webpack.skpm.config.js",
    "content": "const path = require('path');\n\nmodule.exports = (config) => {\n  if (process.env.LOCAL_DEV) {\n    config.resolve = {\n      ...config.resolve,\n      alias: {\n        ...config.resolve.alias,\n        'react-sketchapp': path.resolve(__dirname, '../../'),\n      },\n    };\n  }\n};\n"
  },
  {
    "path": "examples/profile-cards/README.md",
    "content": "# Profile Cards\n\n## How to use\n\nDownload the example or [clone the repo](http://github.com/airbnb/react-sketchapp):\n\n```bash\ncurl https://codeload.github.com/airbnb/react-sketchapp/tar.gz/master | tar -xz --strip=2 react-sketchapp-master/examples/profile-cards\ncd profile-cards\n```\n\nInstall the dependencies\n\n```bash\nnpm install\n```\n\nThen, open Sketch and navigate to `Plugins → react-sketchapp: Profile Cards`\n\nRun with live reloading in Sketch\n\n```bash\nnpm run render\n```\n\n## The idea behind the example\n\n`react-sketchapp` makes it simple to compose components and see how they perform with real data.\n\n![examples-profile-cards](https://cloud.githubusercontent.com/assets/591643/24778173/0dd7c03c-1ade-11e7-8bad-1ad51fe1033e.png)\n"
  },
  {
    "path": "examples/profile-cards/package.json",
    "content": "{\n  \"name\": \"profile-cards\",\n  \"private\": true,\n  \"skpm\": {\n    \"main\": \"profile-cards.sketchplugin\",\n    \"manifest\": \"src/manifest.json\"\n  },\n  \"scripts\": {\n    \"build\": \"skpm-build\",\n    \"watch\": \"skpm-build --watch\",\n    \"render\": \"skpm-build --watch --run\",\n    \"render:once\": \"skpm-build --run\",\n    \"postinstall\": \"npm run build && skpm-link\"\n  },\n  \"author\": \"Jon Gold <jon.gold@airbnb.com>\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"react\": \"^16.3.2\",\n    \"react-sketchapp\": \"^3.0.0\",\n    \"react-test-renderer\": \"^16.3.2\"\n  },\n  \"devDependencies\": {\n    \"@skpm/builder\": \"^0.4.0\"\n  }\n}\n"
  },
  {
    "path": "examples/profile-cards/src/components/Profile.js",
    "content": "import * as React from 'react';\nimport { Image, View, Text, StyleSheet } from 'react-sketchapp';\nimport { colors, fonts, spacing } from '../designSystem';\n\nconst styles = StyleSheet.create({\n  container: {\n    backgroundColor: colors.Haus,\n    padding: 20,\n    width: 260,\n  },\n  avatar: {\n    height: 220,\n    resizeMode: 'contain',\n    marginBottom: 20,\n    borderRadius: 10,\n  },\n  title: fonts['Title 2'],\n  subtitle: fonts['Title 3'],\n  body: fonts.Body,\n});\n\nconst Avatar = ({ url }) => <Image source={url} style={styles.avatar} />;\n\nconst Title = ({ children }) => <Text style={styles.title}>{children}</Text>;\n\nconst Subtitle = ({ children }) => <Text style={styles.subtitle}>{children}</Text>;\n\nconst Body = ({ children }) => <Text style={styles.body}>{children}</Text>;\n\nconst Profile = props => (\n  <View style={styles.container}>\n    <Avatar url={props.user.profile_image_url} />\n    <View style={{ marginBottom: spacing }}>\n      <Title>{props.user.name}</Title>\n      <Subtitle>{`@${props.user.screen_name}`}</Subtitle>\n    </View>\n    <Body>{props.user.description}</Body>\n    <Body>{props.user.location}</Body>\n    <Body>{props.user.url}</Body>\n  </View>\n);\n\nexport default Profile;\n"
  },
  {
    "path": "examples/profile-cards/src/components/Space.js",
    "content": "import * as React from 'react';\nimport { View } from 'react-sketchapp';\n\nconst Space = ({ h, v, children }) => (\n  <View\n    style={{\n      paddingHorizontal: h,\n      paddingVertical: v,\n    }}\n  >\n    {children}\n  </View>\n);\n\nexport default Space;\n"
  },
  {
    "path": "examples/profile-cards/src/designSystem.js",
    "content": "export const colors = {\n  Haus: '#F3F4F4',\n  Night: '#333',\n  Sur: '#96DBE4',\n  'Sur a11y': '#24828F',\n  Peach: '#EFADA0',\n  'Peach a11y': '#E37059',\n  Pear: '#93DAAB',\n  'Pear a11y': '#2E854B',\n};\n\nconst typeSizes = [80, 48, 36, 24, 20, 16];\n\nexport const spacing = 16;\n\nconst fontFamilies = {\n  display: 'Helvetica',\n  body: 'Georgia',\n};\n\nconst fontWeights = {\n  regular: 'regular',\n  bold: 'bold',\n};\n\nexport const fonts = {\n  Headline: {\n    color: colors.Night,\n    fontSize: typeSizes[0],\n    fontFamily: fontFamilies.display,\n    fontWeight: fontWeights.bold,\n    lineHeight: 80,\n  },\n  'Title 1': {\n    color: colors.Night,\n    fontSize: typeSizes[2],\n    fontFamily: fontFamilies.display,\n    fontWeight: fontWeights.bold,\n    lineHeight: 48,\n  },\n  'Title 2': {\n    color: colors.Night,\n    fontSize: typeSizes[3],\n    fontFamily: fontFamilies.display,\n    fontWeight: fontWeights.bold,\n    lineHeight: 36,\n  },\n  'Title 3': {\n    color: colors.Night,\n    fontSize: typeSizes[4],\n    fontFamily: fontFamilies.body,\n    fontWeight: fontWeights.regular,\n    lineHeight: 24,\n  },\n  Body: {\n    color: colors.Night,\n    fontSize: typeSizes[5],\n    fontFamily: fontFamilies.body,\n    fontWeight: fontWeights.regular,\n    lineHeight: 24,\n    marginBottom: 24,\n  },\n};\n\nexport default {\n  colors,\n  fonts,\n  spacing,\n};\n"
  },
  {
    "path": "examples/profile-cards/src/main.js",
    "content": "import * as React from 'react';\nimport { render, Text, View } from 'react-sketchapp';\nimport { fonts, spacing } from './designSystem';\nimport Profile from './components/Profile';\nimport Space from './components/Space';\n\nconst Page = ({ users }) => (\n  <View>\n    <Text style={fonts['Title 1']}>Profile Cards</Text>\n    <View\n      style={{\n        flexDirection: 'row',\n        flexWrap: 'wrap',\n        width: users.length * 300,\n      }}\n    >\n      {users.map((user) => (\n        <Space key={user.screen_name} h={spacing} v={spacing}>\n          <Profile user={user} />\n        </Space>\n      ))}\n    </View>\n  </View>\n);\n\nexport default () => {\n  const DATA = [\n    {\n      screen_name: 'mxstbr',\n      name: 'Max Stoiber',\n      description:\n        '⚛️ Makes styled-components, react-boilerplate, @KeystoneJS and CarteBlanche. ✌ Open source developer @thethinkmill. ☕ Speciality coffee geek, skier, traveller.',\n      location: 'Vienna, Austria',\n      url: 'mxstbr.com',\n      profile_image_url:\n        'https://pbs.twimg.com/profile_images/763033229993574400/6frGyDyA_400x400.jpg',\n    },\n    {\n      name: '- ̗̀Jackie ̖́-',\n      screen_name: 'jackiesaik',\n      description:\n        'Graphic designer, never won a spelling be. Toronto on weekdays. Go Home Lake on weekends. ╮ (. ● ᴗ ●.) ╭',\n      location: 'Toronto, ON',\n      url: 'cargocollective.com/jackiesaik',\n      profile_image_url:\n        'https://pbs.twimg.com/profile_images/895665264464764930/7Mb3QtEB_400x400.jpg',\n    },\n    {\n      screen_name: 'jongold',\n      name: 'kerning man',\n      description:\n        'an equal command of technology and form • functional programming (oc)cultist • design tools @airbnbdesign',\n      location: 'California',\n      url: 'weirdwideweb.jon.gold',\n      profile_image_url: 'https://pbs.twimg.com/profile_images/833785170285178881/loBb32g3.jpg',\n    },\n  ];\n\n  render(<Page users={DATA} />, context.document.currentPage());\n};\n"
  },
  {
    "path": "examples/profile-cards/src/manifest.json",
    "content": "{\n  \"compatibleVersion\": 1,\n  \"bundleVersion\": 1,\n  \"commands\": [\n    {\n      \"name\": \"react-sketchapp: Profile Cards\",\n      \"identifier\": \"main\",\n      \"script\": \"./main.js\"\n    }\n  ],\n  \"menu\": {\n    \"isRoot\": true,\n    \"items\": [\n      \"main\"\n    ]\n  }\n}\n"
  },
  {
    "path": "examples/profile-cards/webpack.skpm.config.js",
    "content": "const path = require('path');\n\nmodule.exports = (config) => {\n  if (process.env.LOCAL_DEV) {\n    config.resolve = {\n      ...config.resolve,\n      alias: {\n        ...config.resolve.alias,\n        'react-sketchapp': path.resolve(__dirname, '../../'),\n      },\n    };\n  }\n};\n"
  },
  {
    "path": "examples/profile-cards-graphql/README.md",
    "content": "# Profile Cards w/ GraphQL\n\n## How to use\n\nDownload the example or [clone the repo](http://github.com/airbnb/react-sketchapp):\n\n```bash\ncurl https://codeload.github.com/airbnb/react-sketchapp/tar.gz/master | tar -xz --strip=2 react-sketchapp-master/examples/profile-cards-graphql\ncd profile-cards-graphql\n```\n\nInstall the dependencies\n\n```bash\nnpm install\n```\n\nThen, open Sketch and navigate to `Plugins → react-sketchapp: Profile Cards w/ GraphQL`\n\nRun with live reloading in Sketch\n\n```bash\nnpm run render\n```\n\n## The idea behind the example\n\nBuilding on the [Profile Cards example](../profile-cards), it's simple to fetch real data for your mockups with GraphQL!\n\n![examples-profile-cards-gql](https://cloud.githubusercontent.com/assets/591643/24778175/0dda21d8-1ade-11e7-9545-13b472263ff6.png)\n"
  },
  {
    "path": "examples/profile-cards-graphql/package.json",
    "content": "{\n  \"name\": \"profile-cards-gql\",\n  \"version\": \"1.0.0\",\n  \"skpm\": {\n    \"main\": \"profile-cards-gql.sketchplugin\",\n    \"manifest\": \"src/manifest.json\"\n  },\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"skpm-build\",\n    \"watch\": \"skpm-build --watch\",\n    \"render\": \"skpm-build --watch --run\",\n    \"render:once\": \"skpm-build --run\",\n    \"postinstall\": \"npm run build && skpm-link\"\n  },\n  \"author\": \"Jon Gold <jon.gold@airbnb.com>\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"apollo-cache-inmemory\": \"^1.1.11\",\n    \"apollo-client\": \"^2.2.7\",\n    \"apollo-link-http\": \"^1.5.3\",\n    \"graphql\": \"^0.13.2\",\n    \"graphql-tag\": \"^2.4.0\",\n    \"react\": \"^16.3.2\",\n    \"react-apollo\": \"^2.1.0\",\n    \"react-sketchapp\": \"^3.0.0\",\n    \"react-test-renderer\": \"^16.3.2\"\n  },\n  \"devDependencies\": {\n    \"@skpm/builder\": \"^0.4.0\"\n  }\n}\n"
  },
  {
    "path": "examples/profile-cards-graphql/src/components/Profile.js",
    "content": "import * as React from 'react';\nimport { Image, View, Text, StyleSheet } from 'react-sketchapp';\nimport { colors, fonts, spacing } from '../designSystem';\n\nconst styles = StyleSheet.create({\n  container: {\n    backgroundColor: colors.Haus,\n    padding: 20,\n    width: 260,\n  },\n  avatar: {\n    height: 220,\n    resizeMode: 'contain',\n    marginBottom: 20,\n    borderRadius: 10,\n  },\n  title: fonts['Title 2'],\n  subtitle: fonts['Title 3'],\n  body: fonts.Body,\n});\n\nconst Avatar = ({ url }) => <Image source={url} style={styles.avatar} />;\n\nconst Title = ({ children }) => <Text style={styles.title}>{children}</Text>;\n\nconst Subtitle = ({ children }) => <Text style={styles.subtitle}>{children}</Text>;\n\nconst Body = ({ children }) => <Text style={styles.body}>{children}</Text>;\n\nconst Profile = props => (\n  <View style={styles.container}>\n    <Avatar url={props.user.profileImageUrl} />\n    <View style={{ marginBottom: spacing }}>\n      <Title>{props.user.name}</Title>\n      <Subtitle>@{props.user.screenname}</Subtitle>\n    </View>\n    <Body>{props.user.description}</Body>\n    <Body>{props.user.location}</Body>\n    <Body>{props.user.url}</Body>\n  </View>\n);\n\nexport default Profile;\n"
  },
  {
    "path": "examples/profile-cards-graphql/src/components/Space.js",
    "content": "import * as React from 'react';\nimport { View } from 'react-sketchapp';\n\nconst Space = ({ h, v, children }) => (\n  <View\n    style={{\n      paddingHorizontal: h,\n      paddingVertical: v,\n    }}\n  >\n    {children}\n  </View>\n);\n\nexport default Space;\n"
  },
  {
    "path": "examples/profile-cards-graphql/src/designSystem.js",
    "content": "export const colors = {\n  Haus: '#F3F4F4',\n  Night: '#333',\n  Sur: '#96DBE4',\n  'Sur a11y': '#24828F',\n  Peach: '#EFADA0',\n  'Peach a11y': '#E37059',\n  Pear: '#93DAAB',\n  'Pear a11y': '#2E854B',\n};\n\nconst typeSizes = [80, 48, 36, 24, 20, 16];\n\nexport const spacing = 16;\n\nconst fontFamilies = {\n  display: 'Helvetica',\n  body: 'Georgia',\n};\n\nconst fontWeights = {\n  regular: 'regular',\n  bold: 'bold',\n};\n\nexport const fonts = {\n  Headline: {\n    color: colors.Night,\n    fontSize: typeSizes[0],\n    fontFamily: fontFamilies.display,\n    fontWeight: fontWeights.bold,\n    lineHeight: 80,\n  },\n  'Title 1': {\n    color: colors.Night,\n    fontSize: typeSizes[2],\n    fontFamily: fontFamilies.display,\n    fontWeight: fontWeights.bold,\n    lineHeight: 48,\n  },\n  'Title 2': {\n    color: colors.Night,\n    fontSize: typeSizes[3],\n    fontFamily: fontFamilies.display,\n    fontWeight: fontWeights.bold,\n    lineHeight: 36,\n  },\n  'Title 3': {\n    color: colors.Night,\n    fontSize: typeSizes[4],\n    fontFamily: fontFamilies.body,\n    fontWeight: fontWeights.regular,\n    lineHeight: 24,\n  },\n  Body: {\n    color: colors.Night,\n    fontSize: typeSizes[5],\n    fontFamily: fontFamilies.body,\n    fontWeight: fontWeights.regular,\n    lineHeight: 24,\n    marginBottom: 24,\n  },\n};\n\nexport default {\n  colors,\n  fonts,\n  spacing,\n};\n"
  },
  {
    "path": "examples/profile-cards-graphql/src/main.js",
    "content": "import * as React from 'react';\nimport { render, Text, View } from 'react-sketchapp';\nimport { ApolloClient } from 'apollo-client';\nimport { HttpLink } from 'apollo-link-http';\nimport { InMemoryCache } from 'apollo-cache-inmemory';\nimport { graphql, ApolloProvider } from 'react-apollo';\nimport gql from 'graphql-tag';\nimport { fonts, spacing } from './designSystem';\nimport Profile from './components/Profile';\nimport Space from './components/Space';\n\nconst GRAPHQL_ENDPOINT = 'https://api.graph.cool/simple/v1/cj09zm1k4jcpc0115ecsoc1k4';\n\nconst client = new ApolloClient({\n  link: new HttpLink({ uri: GRAPHQL_ENDPOINT }),\n  ssrMode: true,\n  cache: new InMemoryCache(),\n});\n\nconst QUERY = gql`\n  {\n    allProfiles {\n      screenname\n      name\n      description\n      location\n      url\n      profileImageUrl\n    }\n  }\n`;\n\nconst props = ({ data }) => (data.loading ? { users: [] } : { users: data.allProfiles });\nconst withUsers = graphql(QUERY, { props });\n\nconst Page = ({ users }) => (\n  <View>\n    <Text style={fonts['Title 1']}>Profile Cards w/ GraphQL</Text>\n    {users && (\n      <View\n        style={{\n          flexDirection: 'row',\n          flexWrap: 'wrap',\n          width: users.length * 300,\n        }}\n      >\n        {users.map((user) => (\n          <Space key={user.screenname} h={spacing} v={spacing}>\n            <Profile user={user} />\n          </Space>\n        ))}\n      </View>\n    )}\n  </View>\n);\n\nconst PageWithUsers = withUsers(Page);\n\nconst App = () => (\n  <ApolloProvider client={client}>\n    <PageWithUsers />\n  </ApolloProvider>\n);\n\nexport default () => {\n  client\n    .query({ query: QUERY })\n    .then(() => render(<App />, context.document.currentPage()))\n    .catch(console.log);\n};\n"
  },
  {
    "path": "examples/profile-cards-graphql/src/manifest.json",
    "content": "{\n  \"compatibleVersion\": 1,\n  \"bundleVersion\": 1,\n  \"commands\": [\n    {\n      \"name\": \"react-sketchapp: Profile Cards w/ GraphQL\",\n      \"identifier\": \"main\",\n      \"script\": \"./main.js\"\n    }\n  ],\n  \"menu\": {\n    \"isRoot\": true,\n    \"items\": [\n      \"main\"\n    ]\n  }\n}\n"
  },
  {
    "path": "examples/profile-cards-graphql/webpack.skpm.config.js",
    "content": "const path = require('path');\n\nmodule.exports = (config) => {\n  if (process.env.LOCAL_DEV) {\n    config.resolve = {\n      ...config.resolve,\n      alias: {\n        ...config.resolve.alias,\n        'react-sketchapp': path.resolve(__dirname, '../../'),\n      },\n    };\n  }\n};\n"
  },
  {
    "path": "examples/profile-cards-primitives/README.md",
    "content": "# Profile Cards w/ React Primitives\n\n## How to use\n\nDownload the example or [clone the repo](http://github.com/airbnb/react-sketchapp):\n\n```bash\ncurl https://codeload.github.com/airbnb/react-sketchapp/tar.gz/master | tar -xz --strip=2 react-sketchapp-master/examples/profile-cards-primitives\ncd profile-cards-primitives\n```\n\nInstall the dependencies\n\n```bash\nnpm install\n```\n\nThen, open Sketch and navigate to `Plugins → react-sketchapp: Profile Cards w/ Primitives`\n\n### Run it in Sketch\n\nRun with live reloading in Sketch\n\n```bash\nnpm run render\n```\n\n### Run it in your browser\n\n```bash\nnpm run web\n```\n\nOpen a browser to `http://localhost:3000`\n\n## The idea behind the example\n\n`react-primitives` provides a powerful way to build platform-independent components. This is a simple example of rendering to web & Sketch simultaneously.\n\n![examples-primitives](https://cloud.githubusercontent.com/assets/591643/24778174/0dd9d214-1ade-11e7-9372-fa8b578a0b48.png)\n"
  },
  {
    "path": "examples/profile-cards-primitives/nwb.config.js",
    "content": "module.exports = {\n  webpack: {\n    resolve: {\n      // look for .web.js first\n      extensions: ['.web.js', '.js', '.json'],\n    },\n  },\n};\n"
  },
  {
    "path": "examples/profile-cards-primitives/package.json",
    "content": "{\n  \"name\": \"profile-cards-primitives\",\n  \"private\": true,\n  \"skpm\": {\n    \"main\": \"profile-cards-primitives.sketchplugin\",\n    \"manifest\": \"src/manifest.json\"\n  },\n  \"scripts\": {\n    \"build\": \"skpm-build\",\n    \"watch\": \"skpm-build --watch\",\n    \"render\": \"skpm-build --watch --run\",\n    \"render:once\": \"skpm-build --run\",\n    \"postinstall\": \"npm run build && skpm-link\",\n    \"web\": \"react run src/web.js\"\n  },\n  \"author\": \"Jon Gold <jon.gold@airbnb.com>\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"nwb\": \"^0.15.6\",\n    \"react\": \"^16.3.2\",\n    \"react-dom\": \"^15.4.2\",\n    \"react-native\": \"^0.42.3\",\n    \"react-primitives\": \"^0.6.0\",\n    \"react-sketchapp\": \"^3.0.0\",\n    \"react-test-renderer\": \"^16.3.2\"\n  },\n  \"devDependencies\": {\n    \"@skpm/builder\": \"^0.4.0\"\n  }\n}\n"
  },
  {
    "path": "examples/profile-cards-primitives/src/components/Profile.js",
    "content": "import * as React from 'react';\nimport { Image, View, Text, StyleSheet } from 'react-primitives';\nimport { colors, fonts, spacing } from '../designSystem';\n\nconst styles = StyleSheet.create({\n  container: {\n    backgroundColor: colors.Haus,\n    padding: 20,\n    width: 260,\n  },\n  avatar: {\n    height: 220,\n    resizeMode: 'contain',\n    marginBottom: 20,\n    borderRadius: 10,\n  },\n  title: fonts['Title 2'],\n  subtitle: fonts['Title 3'],\n  body: fonts.Body,\n});\n\nconst Avatar = ({ url }) => <Image source={url} style={styles.avatar} />;\n\nconst Title = ({ children }) => <Text style={styles.title}>{children}</Text>;\n\nconst Subtitle = ({ children }) => <Text style={styles.subtitle}>{children}</Text>;\n\nconst Body = ({ children }) => <Text style={styles.body}>{children}</Text>;\n\nconst Profile = (props) => (\n  <View style={styles.container}>\n    <Avatar url={props.user.profile_image_url} />\n    <View style={{ marginBottom: spacing }}>\n      <Title>{props.user.name}</Title>\n      <Subtitle>{`@${props.user.screen_name}`}</Subtitle>\n    </View>\n    <Body>{props.user.description}</Body>\n    <Body>{props.user.location}</Body>\n    <Body>{props.user.url}</Body>\n  </View>\n);\n\nexport default Profile;\n"
  },
  {
    "path": "examples/profile-cards-primitives/src/components/Space.js",
    "content": "import * as React from 'react';\nimport { View } from 'react-primitives';\n\nconst Space = ({ h, v, children }) => (\n  <View\n    style={{\n      paddingHorizontal: h,\n      paddingVertical: v,\n    }}\n  >\n    {children}\n  </View>\n);\n\nexport default Space;\n"
  },
  {
    "path": "examples/profile-cards-primitives/src/data.js",
    "content": "export default [\n  {\n    screen_name: 'mxstbr',\n    name: 'Max Stoiber',\n    description:\n      '⚛️ Makes styled-components, react-boilerplate, @KeystoneJS and CarteBlanche. ✌ Open source developer @thethinkmill. ☕ Speciality coffee geek, skier, traveller.',\n    location: 'Vienna, Austria',\n    url: 'mxstbr.com',\n    profile_image_url:\n      'https://pbs.twimg.com/profile_images/763033229993574400/6frGyDyA_400x400.jpg',\n  },\n  {\n    name: '- ̗̀Jackie ̖́-',\n    screen_name: 'jackiesaik',\n    description:\n      'Graphic designer, never won a spelling be. Toronto on weekdays. Go Home Lake on weekends. ╮ (. ● ᴗ ●.) ╭',\n    location: 'Toronto, ON',\n    url: 'cargocollective.com/jackiesaik',\n    profile_image_url:\n      'https://pbs.twimg.com/profile_images/895665264464764930/7Mb3QtEB_400x400.jpg',\n  },\n  {\n    screen_name: 'jongold',\n    name: 'kerning man',\n    description:\n      'an equal command of technology and form • functional programming (oc)cultist • design tools @airbnbdesign',\n    location: 'California',\n    url: 'weirdwideweb.jon.gold',\n    profile_image_url: 'https://pbs.twimg.com/profile_images/833785170285178881/loBb32g3.jpg',\n  },\n];\n"
  },
  {
    "path": "examples/profile-cards-primitives/src/designSystem.js",
    "content": "export const colors = {\n  Haus: '#F3F4F4',\n  Night: '#333',\n  Sur: '#96DBE4',\n  'Sur a11y': '#24828F',\n  Peach: '#EFADA0',\n  'Peach a11y': '#E37059',\n  Pear: '#93DAAB',\n  'Pear a11y': '#2E854B',\n};\n\nconst typeSizes = [80, 48, 36, 24, 20, 16];\n\nexport const spacing = 16;\n\nconst fontFamilies = {\n  display: 'Helvetica',\n  body: 'Georgia',\n};\n\nconst fontWeights = {\n  regular: 'regular',\n  bold: 'bold',\n};\n\nexport const fonts = {\n  Headline: {\n    color: colors.Night,\n    fontSize: typeSizes[0],\n    fontFamily: fontFamilies.display,\n    fontWeight: fontWeights.bold,\n    lineHeight: 80,\n  },\n  'Title 1': {\n    color: colors.Night,\n    fontSize: typeSizes[2],\n    fontFamily: fontFamilies.display,\n    fontWeight: fontWeights.bold,\n    lineHeight: 48,\n  },\n  'Title 2': {\n    color: colors.Night,\n    fontSize: typeSizes[3],\n    fontFamily: fontFamilies.display,\n    fontWeight: fontWeights.bold,\n    lineHeight: 36,\n  },\n  'Title 3': {\n    color: colors.Night,\n    fontSize: typeSizes[4],\n    fontFamily: fontFamilies.body,\n    fontWeight: fontWeights.regular,\n    lineHeight: 24,\n  },\n  Body: {\n    color: colors.Night,\n    fontSize: typeSizes[5],\n    fontFamily: fontFamilies.body,\n    fontWeight: fontWeights.regular,\n    lineHeight: 24,\n    marginBottom: 24,\n  },\n};\n\nexport default {\n  colors,\n  fonts,\n  spacing,\n};\n"
  },
  {
    "path": "examples/profile-cards-primitives/src/main.js",
    "content": "import * as React from 'react';\nimport { render } from 'react-sketchapp';\nimport { Text, View } from 'react-primitives';\nimport { fonts, spacing } from './designSystem';\nimport Profile from './components/Profile';\nimport Space from './components/Space';\nimport DATA from './data';\n\nconst Page = ({ users }) => (\n  <View>\n    <Text style={fonts['Title 1']}>Profile Cards w/ React Primitives</Text>\n    <View\n      style={{\n        flexDirection: 'row',\n        flexWrap: 'wrap',\n        width: users.length * 300,\n      }}\n    >\n      {users.map((user) => (\n        <Space key={user.screen_name} h={spacing} v={spacing}>\n          <Profile user={user} />\n        </Space>\n      ))}\n    </View>\n  </View>\n);\n\nexport default () => {\n  render(<Page users={DATA} />, context.document.currentPage());\n};\n"
  },
  {
    "path": "examples/profile-cards-primitives/src/manifest.json",
    "content": "{\n  \"compatibleVersion\": 1,\n  \"bundleVersion\": 1,\n  \"commands\": [\n    {\n      \"name\": \"react-sketchapp: Profile Cards w/ Primitives\",\n      \"identifier\": \"main\",\n      \"script\": \"./main.js\"\n    }\n  ],\n  \"menu\": {\n    \"isRoot\": true,\n    \"items\": [\n      \"main\"\n    ]\n  }\n}\n"
  },
  {
    "path": "examples/profile-cards-primitives/src/web.js",
    "content": "import * as React from 'react';\nimport Profile from './components/Profile';\nimport Space from './components/Space';\nimport { spacing } from './designSystem';\nimport DATA from './data';\n\n/*\n * <Profile /> is defined with platform-independent components\n * from react-primitives. We can use it in our web UI, and\n * continue to use primitives, or mix them with DOM elements\n */\nexport default () => (\n  <div>\n    <h1 style={{ fontFamily: \"'SF UI Display', 'San Francisco'\" }}>Cross-platform components!</h1>\n    <p\n      style={{\n        fontFamily: \"'SF UI Text', 'San Francisco'\",\n        maxWidth: '28em',\n        lineHeight: 1.5,\n      }}\n    >\n      &lt;Profile /&gt; is defined with platform-independent components from react-primitives. We\n      can use it in our web UI, and continue to use primitives, or mix them with DOM elements\n    </p>\n    <div style={{ display: 'flex', flexDirection: 'row' }}>\n      {DATA.map((user) => (\n        <Space h={spacing} v={spacing}>\n          <Profile key={user.screen_name} user={user} />\n        </Space>\n      ))}\n    </div>\n  </div>\n);\n"
  },
  {
    "path": "examples/profile-cards-primitives/webpack.skpm.config.js",
    "content": "const path = require('path');\n\nmodule.exports = (config) => {\n  if (process.env.LOCAL_DEV) {\n    config.resolve = {\n      ...config.resolve,\n      alias: {\n        ...config.resolve.alias,\n        'react-sketchapp': path.resolve(__dirname, '../../'),\n      },\n    };\n  }\n};\n"
  },
  {
    "path": "examples/profile-cards-react-with-styles/README.md",
    "content": "# Profile Cards w/ react-with-styles\n\n## How to use\n\nDownload the example or [clone the repo](http://github.com/airbnb/react-sketchapp):\n\n```bash\ncurl https://codeload.github.com/airbnb/react-sketchapp/tar.gz/master | tar -xz --strip=2 react-sketchapp-master/examples/profile-cards-react-with-styles\ncd profile-cards-react-with-styles\n```\n\nInstall the dependencies\n\n```bash\nnpm install\n```\n\nThen, open Sketch and navigate to `Plugins → react-sketchapp: Profile Cards`\n\nRun with live reloading in Sketch\n\n```bash\nnpm run render\n```\n\n## The idea behind the example\n\nUse `react-sketchapp` with [`react-with-styles`](https://github.com/airbnb/react-with-styles) — a library for writing CSS-in-JS without coupling to specific implementations.\n\n![examples-profile-cards](https://cloud.githubusercontent.com/assets/591643/24778173/0dd7c03c-1ade-11e7-8bad-1ad51fe1033e.png)\n"
  },
  {
    "path": "examples/profile-cards-react-with-styles/package.json",
    "content": "{\n  \"name\": \"profile-cards-react-with-styles\",\n  \"private\": true,\n  \"skpm\": {\n    \"main\": \"profile-cards-react-with-styles.sketchplugin\",\n    \"manifest\": \"src/manifest.json\"\n  },\n  \"scripts\": {\n    \"build\": \"skpm-build\",\n    \"watch\": \"skpm-build --watch\",\n    \"render\": \"skpm-build --watch --run\",\n    \"render:once\": \"skpm-build --run\",\n    \"postinstall\": \"npm run build && skpm-link\"\n  },\n  \"author\": \"Jon Gold <jon.gold@airbnb.com>\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"react\": \"^16.3.2\",\n    \"react-sketchapp\": \"^3.0.0\",\n    \"react-test-renderer\": \"^16.3.2\",\n    \"react-with-styles\": \"^1.4.0\"\n  },\n  \"devDependencies\": {\n    \"@skpm/builder\": \"^0.4.0\"\n  }\n}\n"
  },
  {
    "path": "examples/profile-cards-react-with-styles/src/components/Profile.js",
    "content": "import * as React from 'react';\nimport { Image, View, Text } from 'react-sketchapp';\nimport { css, withStyles } from '../withStyles';\n\nconst Profile = ({ user, styles }) => (\n  <View {...css(styles.container)}>\n    <Image source={user.profile_image_url} {...css(styles.avatar)} />\n    <View {...css(styles.titleWrapper)}>\n      <Text {...css(styles.title)}>{user.name}</Text>\n      <Text {...css(styles.subtitle)}>{`@${user.screen_name}`}</Text>\n    </View>\n    <Text {...css(styles.body)}>{user.description}</Text>\n    <Text {...css(styles.body)}>{user.location}</Text>\n    <Text {...css(styles.body)}>{user.url}</Text>\n  </View>\n);\n\nexport default withStyles(({ colors, fonts, spacing }) => ({\n  container: {\n    backgroundColor: colors.Haus,\n    padding: spacing,\n    width: 260,\n    marginRight: spacing,\n  },\n  avatar: {\n    height: 220,\n    resizeMode: 'contain',\n    marginBottom: spacing * 2,\n    borderRadius: 10,\n  },\n  titleWrapper: {\n    marginBottom: spacing,\n  },\n  title: { ...fonts['Title 2'] },\n  subtitle: { ...fonts['Title 3'] },\n  body: { ...fonts.Body },\n}))(Profile);\n"
  },
  {
    "path": "examples/profile-cards-react-with-styles/src/main.js",
    "content": "import * as React from 'react';\nimport { render, Text, View } from 'react-sketchapp';\nimport Profile from './components/Profile';\nimport { css, withStyles } from './withStyles';\n\nconst Title = withStyles(({ fonts }) => ({\n  titleText: fonts['Title 1'],\n}))(({ children, styles }) => <Text {...css(styles.titleText)}>{children}</Text>);\n\nconst Page = ({ users }) => (\n  <View>\n    <Title>Profile Cards w/ react-with-styles</Title>\n    <View\n      style={{\n        flexDirection: 'row',\n        flexWrap: 'wrap',\n        width: users.length * 300,\n      }}\n    >\n      {users.map((user) => (\n        <Profile user={user} />\n      ))}\n    </View>\n  </View>\n);\n\nexport default () => {\n  const DATA = [\n    {\n      screen_name: 'jaredpalmer',\n      name: 'Jared Palmer',\n      description: 'Engineer @PalmerGroupHQ',\n      location: 'New York, NY',\n      url: 'github.com/jaredpalmer',\n      profile_image_url: 'https://pbs.twimg.com/profile_images/662984079638405120/Y6oncSaf.jpg',\n    },\n    {\n      name: '- ̗̀Jackie ̖́-',\n      screen_name: 'jackiesaik',\n      description:\n        'Graphic designer, never won a spelling be. Toronto on weekdays. Go Home Lake on weekends. ╮ (. ● ᴗ ●.) ╭',\n      location: 'Toronto, ON',\n      url: 'cargocollective.com/jackiesaik',\n      profile_image_url:\n        'https://pbs.twimg.com/profile_images/895665264464764930/7Mb3QtEB_400x400.jpg',\n    },\n    {\n      screen_name: 'jongold',\n      name: 'kerning man',\n      description:\n        'an equal command of technology and form • functional programming (oc)cultist • design tools @airbnbdesign',\n      location: 'California',\n      url: 'weirdwideweb.jon.gold',\n      profile_image_url: 'https://pbs.twimg.com/profile_images/833785170285178881/loBb32g3.jpg',\n    },\n  ];\n\n  render(<Page users={DATA} />, context.document.currentPage());\n};\n"
  },
  {
    "path": "examples/profile-cards-react-with-styles/src/manifest.json",
    "content": "{\n  \"compatibleVersion\": 1,\n  \"bundleVersion\": 1,\n  \"commands\": [\n    {\n      \"name\": \"react-sketchapp: Profile Cards w/ react-with-styles\",\n      \"identifier\": \"main\",\n      \"script\": \"./main.js\"\n    }\n  ],\n  \"menu\": {\n    \"isRoot\": true,\n    \"items\": [\n      \"main\"\n    ]\n  }\n}\n"
  },
  {
    "path": "examples/profile-cards-react-with-styles/src/theme.js",
    "content": "export const colors = {\n  Haus: '#F3F4F4',\n  Night: '#333',\n  Sur: '#96DBE4',\n  'Sur a11y': '#24828F',\n  Peach: '#EFADA0',\n  'Peach a11y': '#E37059',\n  Pear: '#93DAAB',\n  'Pear a11y': '#2E854B',\n};\n\nconst typeSizes = [80, 48, 36, 24, 20, 16];\n\nexport const spacing = 16;\n\nconst fontFamilies = {\n  display: 'Helvetica',\n  body: 'Georgia',\n};\n\nconst fontWeights = {\n  regular: 'regular',\n  bold: 'bold',\n};\n\nexport const fonts = {\n  Headline: {\n    color: colors.Night,\n    fontSize: typeSizes[0],\n    fontFamily: fontFamilies.display,\n    fontWeight: fontWeights.bold,\n    lineHeight: 80,\n  },\n  'Title 1': {\n    color: colors.Night,\n    fontSize: typeSizes[2],\n    fontFamily: fontFamilies.display,\n    fontWeight: fontWeights.bold,\n    lineHeight: 48,\n  },\n  'Title 2': {\n    color: colors.Night,\n    fontSize: typeSizes[3],\n    fontFamily: fontFamilies.display,\n    fontWeight: fontWeights.bold,\n    lineHeight: 36,\n  },\n  'Title 3': {\n    color: colors.Night,\n    fontSize: typeSizes[4],\n    fontFamily: fontFamilies.body,\n    fontWeight: fontWeights.regular,\n    lineHeight: 24,\n  },\n  Body: {\n    color: colors.Night,\n    fontSize: typeSizes[5],\n    fontFamily: fontFamilies.body,\n    fontWeight: fontWeights.regular,\n    lineHeight: 24,\n    marginBottom: 24,\n  },\n};\n\nexport default {\n  colors,\n  fonts,\n  spacing,\n};\n"
  },
  {
    "path": "examples/profile-cards-react-with-styles/src/types.js",
    "content": "export type User = {\n  screen_name: string,\n  name: string,\n  description: string,\n  profile_image_url: string,\n  location: string,\n  url: string,\n};\n"
  },
  {
    "path": "examples/profile-cards-react-with-styles/src/withStyles.js",
    "content": "import ThemedStyleSheet from 'react-with-styles/lib/ThemedStyleSheet';\nimport { css, withStyles, ThemeProvider } from 'react-with-styles';\nimport { StyleSheet } from 'react-sketchapp';\n\nimport theme from './theme';\n\nconst Interface = {\n  create(styleHash) {\n    return StyleSheet.create(styleHash);\n  },\n\n  resolve(styles) {\n    return { style: styles };\n  },\n};\n\nThemedStyleSheet.registerDefaultTheme(theme);\nThemedStyleSheet.registerInterface(Interface);\n\nexport { css, withStyles, ThemeProvider, ThemedStyleSheet };\n"
  },
  {
    "path": "examples/profile-cards-react-with-styles/webpack.skpm.config.js",
    "content": "const path = require('path');\n\nmodule.exports = (config) => {\n  if (process.env.LOCAL_DEV) {\n    config.resolve = {\n      ...config.resolve,\n      alias: {\n        ...config.resolve.alias,\n        'react-sketchapp': path.resolve(__dirname, '../../'),\n      },\n    };\n  }\n};\n"
  },
  {
    "path": "examples/react-router-prototyping/README.md",
    "content": "# React Router setup\n\n## How to use\n\nDownload the example or [clone the repo](http://github.com/airbnb/react-sketchapp):\n\n```bash\ncurl https://codeload.github.com/airbnb/react-sketchapp/tar.gz/master | tar -xz --strip=2 react-sketchapp-master/examples/react-router-prototyping\ncd react-router-prototyping\n```\n\nInstall the dependencies\n\n```bash\nnpm install\n```\n\nThen, open Sketch and navigate to `Plugins → react-sketchapp: React Router prototyping`\n\nRun with live reloading in Sketch, need a new sketch doc open\n\n```bash\nnpm run render\n```\n\n## The idea behind the example\n\n`react-sketchapp` allows you to build prototypes with navigation. This example shows how you build a Sketch prototype with `react-sketchapp-router`, while being able to share your routing code with your React web or React Native app.\n\n![examples-react-router](https://user-images.githubusercontent.com/6757532/76151291-57fb9100-60ab-11ea-8b07-60916eac0a6e.png)\n"
  },
  {
    "path": "examples/react-router-prototyping/package.json",
    "content": "{\n  \"name\": \"react-router-prototyping\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"skpm\": {\n    \"main\": \"react-router-prototyping.sketchplugin\",\n    \"manifest\": \"src/manifest.json\"\n  },\n  \"scripts\": {\n    \"build\": \"skpm-build\",\n    \"watch\": \"skpm-build --watch\",\n    \"render\": \"skpm-build --watch --run\",\n    \"render:once\": \"skpm-build --run\",\n    \"postinstall\": \"npm run build && skpm-link\"\n  },\n  \"author\": \"Macintosh Helper <github@macintoshhelper.com>\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@skpm/builder\": \"^0.4.3\"\n  },\n  \"dependencies\": {\n    \"prop-types\": \"^15.5.8\",\n    \"react\": \"^16.13.0\",\n    \"react-router-primitives\": \"^0.1.2\",\n    \"react-sketchapp\": \"^3.1.0\",\n    \"react-sketchapp-router\": \"^0.1.3\",\n    \"react-test-renderer\": \"^16.13.0\"\n  }\n}\n"
  },
  {
    "path": "examples/react-router-prototyping/src/App.js",
    "content": "import React from 'react';\nimport { SketchRouter, Switch, Route } from 'react-sketchapp-router';\n\nimport Home from './routes/home';\nimport About from './routes/about';\nimport Post from './routes/post';\nimport Profile from './routes/profile';\n\nconst App = () => (\n  <SketchRouter\n    locations={['/profile/john', '/post/1']}\n    viewport={{ name: 'Mobile', width: 360, height: 640 }}\n  >\n    {/* (Need to have menus/sidebars inside of a Route) */}\n    <Switch>\n      <Route path=\"/\" exact render={({ location }) => <Home />} />\n      <Route path=\"/about\" render={() => <About />} />\n      <Route path=\"/post/:id\" render={({ match: { params } }) => <Post {...params} />} />\n      <Route path=\"/profile/:user\" render={({ match: { params } }) => <Profile {...params} />} />\n      {/* <Route render={() => <NotFound />} /> */}\n    </Switch>\n  </SketchRouter>\n);\n\nexport default App;\n"
  },
  {
    "path": "examples/react-router-prototyping/src/components/AppBar.js",
    "content": "import React from 'react';\nimport { View, Text } from 'react-sketchapp';\nimport { Link } from 'react-router-primitives';\n\nconst AppBar = () => (\n  <Link to=\"/\">\n    <View\n      style={{\n        backgroundColor: '#fff',\n        height: 80,\n        paddingLeft: 16,\n        paddingRight: 16,\n      }}\n    >\n      <View\n        style={{\n          flex: 1,\n          alignItems: 'center',\n          justifyContent: 'center',\n          flexDirection: 'row',\n          borderBottomWidth: 1,\n          borderBottomColor: '#e6e6e6',\n          borderBottomStyle: 'solid',\n        }}\n      >\n        <Text style={{ fontSize: 32, fontWeight: 'bold' }}>My Blog</Text>\n      </View>\n    </View>\n  </Link>\n);\n\nexport default AppBar;\n"
  },
  {
    "path": "examples/react-router-prototyping/src/components/NavBar.js",
    "content": "import React from 'react';\nimport { View, Text } from 'react-sketchapp';\nimport { Link } from 'react-router-primitives';\n\nconst MenuItem = ({ name, href }) => (\n  <Link to={href}>\n    <View style={{ padding: 8 }}>\n      <Text style={{ fontSize: 16, fontFamily: 'Helvetica Neue', color: '#0072ce' }}>{name}</Text>\n    </View>\n  </Link>\n);\n\nconst NavBar = () => (\n  <View\n    style={{\n      height: 40,\n      width: '100%',\n      backgroundColor: 'white',\n      flexDirection: 'row',\n      justifyContent: 'space-around',\n      alignItems: 'center',\n    }}\n  >\n    {[{ name: 'About Us', href: '/about' }].map((props) => (\n      <MenuItem {...props} />\n    ))}\n  </View>\n);\n\nexport default NavBar;\n"
  },
  {
    "path": "examples/react-router-prototyping/src/main.js",
    "content": "/* global context */\nimport * as React from 'react';\nimport { render, Page, Document as RootDocument } from 'react-sketchapp';\n\nimport App from './App';\n\nconst pages = [\n  {\n    name: 'App',\n    component: App,\n  },\n];\n\nconst Document = () => (\n  <RootDocument>\n    {pages.map(({ name, component: Component }) => (\n      <Page name={name}>\n        <Component />\n      </Page>\n    ))}\n  </RootDocument>\n);\n\nexport default () => {\n  const data = context.document.documentData();\n  const pages = context.document.pages();\n\n  data.setCurrentPage(pages.firstObject());\n\n  render(<Document />);\n};\n"
  },
  {
    "path": "examples/react-router-prototyping/src/manifest.json",
    "content": "{\n\t\"compatibleVersion\": 3,\n\t\"bundleVersion\": 1,\n\t\"commands\": [\n\t\t{\n\t\t\t\"name\": \"react-sketchapp: React Router prototyping\",\n\t\t\t\"identifier\": \"main\",\n\t\t\t\"script\": \"./main.js\"\n\t\t}\n\t],\n\t\"menu\": {\n\t\t\"isRoot\": true,\n\t\t\"items\": [\n\t\t\t\"main\"\n\t\t]\n\t}\n}\n"
  },
  {
    "path": "examples/react-router-prototyping/src/routes/about.js",
    "content": "import React from 'react';\nimport { View, Text } from 'react-sketchapp';\n\nimport AppBar from '../components/AppBar';\n\nconst About = () => (\n  <View style={{ flex: 1, backgroundColor: '#fff' }}>\n    <AppBar />\n    <View style={{ height: 100, width: '100%', justifyContent: 'center', alignItems: 'center' }}>\n      <Text style={{ fontSize: 32, color: 'black' }}>About Us</Text>\n    </View>\n    <View style={{ height: 200, width: '100%', padding: 40 }}>\n      <Text style={{ fontSize: 20, color: 'black' }}>\n        There is not a lot of information here about us.\n      </Text>\n    </View>\n  </View>\n);\n\nexport default About;\n"
  },
  {
    "path": "examples/react-router-prototyping/src/routes/home.js",
    "content": "import React from 'react';\nimport { View, Text } from 'react-sketchapp';\nimport { Link } from 'react-router-primitives';\n\nimport AppBar from '../components/AppBar';\nimport NavBar from '../components/NavBar';\n\nconst PostSummary = () => (\n  <Link to=\"/post/1\">\n    <View style={{ flexDirection: 'column' }}>\n      <View style={{ backgroundColor: '#E2E2E2', height: 200, width: '100%' }} />\n      <View style={{ padding: 16 }}>\n        <Text style={{ fontSize: 24 }}>Title of a Blog Post</Text>\n        <Text style={{ marginTop: 12 }}>\n          Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt\n          ut labore et dolore magna aliqua.\n        </Text>\n        <Text style={{ color: '#0072ce' }}>\n          <Text style={{ fontWeight: 'bold' }}>{`> `}</Text>\n          Click here to read more\n        </Text>\n      </View>\n    </View>\n  </Link>\n);\n\nconst Home = () => (\n  <View style={{ flex: 1, backgroundColor: '#fff' }}>\n    <AppBar />\n    <NavBar />\n    <View>\n      <PostSummary />\n    </View>\n  </View>\n);\n\nexport default Home;\n"
  },
  {
    "path": "examples/react-router-prototyping/src/routes/post.js",
    "content": "import React from 'react';\nimport { View, Text } from 'react-sketchapp';\nimport { Link } from 'react-router-primitives';\n\nimport AppBar from '../components/AppBar';\nimport NavBar from '../components/NavBar';\n\nconst posts = {\n  '1': {\n    title: 'Title of a Blog Post',\n    content:\n      'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',\n    author: {\n      id: 'john',\n      name: 'John',\n    },\n  },\n};\n\nconst Post = ({ id }) => {\n  return (\n    <View style={{ flex: 1, backgroundColor: '#fff' }}>\n      <AppBar />\n      <NavBar />\n      {id && (\n        <View style={{ flexDirection: 'column' }}>\n          <View style={{ backgroundColor: '#E2E2E2', height: 400, width: '100%' }} />\n          <View style={{ padding: 16 }}>\n            <Text style={{ fontSize: 32, marginBottom: 16 }}>{posts[id].title}</Text>\n            <Link to={`/profile/${posts[id].author.id}`}>\n              <View style={{ flexDirection: 'row', alignItems: 'center' }}>\n                <View\n                  style={{\n                    borderRadius: '50%',\n                    width: 40,\n                    height: 40,\n                    backgroundColor: '#dedede',\n                    marginRight: 16,\n                  }}\n                />\n                <Text style={{ fontSize: 20, color: 'black' }}>{posts[id].author.name}</Text>\n              </View>\n            </Link>\n            <Text style={{ marginTop: 12 }}>{posts[id].content}</Text>\n          </View>\n        </View>\n      )}\n    </View>\n  );\n};\n\nexport default Post;\n"
  },
  {
    "path": "examples/react-router-prototyping/src/routes/profile.js",
    "content": "import React from 'react';\nimport { View, Text } from 'react-sketchapp';\n\nimport AppBar from '../components/AppBar';\nimport NavBar from '../components/NavBar';\n\nconst Profile = ({ user }) => {\n  const name = user ? `${user.charAt(0).toUpperCase()}${user.slice(1)}` : 'User not found';\n\n  return (\n    <View style={{ flex: 1, backgroundColor: '#fff' }}>\n      <AppBar />\n      <NavBar />\n      <View style={{ height: 200, width: '100%', justifyContent: 'center', alignItems: 'center' }}>\n        <Text style={{ fontSize: 20, color: 'black' }}>{name}</Text>\n      </View>\n    </View>\n  );\n};\n\nexport default Profile;\n"
  },
  {
    "path": "examples/react-router-prototyping/webpack.skpm.config.js",
    "content": "const path = require('path');\n\nmodule.exports = (config) => {\n  if (process.env.LOCAL_DEV) {\n    config.resolve = {\n      ...config.resolve,\n      alias: {\n        ...config.resolve.alias,\n        'react-sketchapp': path.resolve(__dirname, '../../'),\n      },\n    };\n  }\n};\n"
  },
  {
    "path": "examples/styled-components/README.md",
    "content": "# Styled-components\n\n## How to use\n\nDownload the example or [clone the repo](http://github.com/airbnb/react-sketchapp):\n\n```bash\ncurl https://codeload.github.com/airbnb/react-sketchapp/tar.gz/master | tar -xz --strip=2 react-sketchapp-master/examples/styled-components\ncd styled-components\n```\n\nInstall the dependencies\n\n```bash\nnpm install\n```\n\nThen, open Sketch and navigate to `Plugins → react-sketchapp: Styled components`\n\n### Run it in Sketch\n\nRun with live reloading in Sketch\n\n```bash\nnpm run render\n```\n\n## The idea behind the example\n\n`styled-components` allows you to write actual CSS code to style your components. It also removes the mapping between components and styles\n"
  },
  {
    "path": "examples/styled-components/package.json",
    "content": "{\n  \"name\": \"styled-components-example\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"skpm\": {\n    \"main\": \"styled-components.sketchplugin\",\n    \"manifest\": \"src/manifest.json\"\n  },\n  \"scripts\": {\n    \"build\": \"skpm-build\",\n    \"watch\": \"skpm-build --watch\",\n    \"render\": \"skpm-build --watch --run\",\n    \"render:once\": \"skpm-build --run\",\n    \"postinstall\": \"npm run build && skpm-link\"\n  },\n  \"author\": \"Mathieu Dutour <mathieu@dutour.me>\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@skpm/builder\": \"^0.4.0\"\n  },\n  \"dependencies\": {\n    \"chroma-js\": \"^1.2.2\",\n    \"prop-types\": \"^15.5.8\",\n    \"react\": \"^16.3.2\",\n    \"react-primitives\": \"^0.6.0\",\n    \"react-sketchapp\": \"^3.0.0\",\n    \"react-test-renderer\": \"^16.3.2\",\n    \"styled-components\": \"^2.1.0\"\n  }\n}\n"
  },
  {
    "path": "examples/styled-components/src/manifest.json",
    "content": "{\n\t\"compatibleVersion\": 3,\n\t\"bundleVersion\": 1,\n\t\"commands\": [\n\t\t{\n\t\t\t\"name\": \"react-sketchapp: Styled components\",\n\t\t\t\"identifier\": \"main\",\n\t\t\t\"script\": \"./my-command.js\"\n\t\t}\n\t],\n\t\"menu\": {\n\t\t\"isRoot\": true,\n\t\t\"items\": [\n\t\t\t\"main\"\n\t\t]\n\t}\n}\n"
  },
  {
    "path": "examples/styled-components/src/my-command.js",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport styled from 'styled-components/primitives';\nimport { render } from 'react-sketchapp';\nimport chroma from 'chroma-js';\n\n// take a hex and give us a nice text color to put over it\nconst textColor = (hex) => {\n  const vsWhite = chroma.contrast(hex, 'white');\n  if (vsWhite > 4) {\n    return '#FFF';\n  }\n  return chroma(hex).darken(3).hex();\n};\n\nconst SwatchTile = styled.View`\n  height: 250px;\n  width: 250px;\n  border-radius: 4px;\n  margin: 4px;\n  background-color: ${(props) => props.hex};\n  justify-content: center;\n  align-items: center;\n`;\n\nconst SwatchName = styled.Text`\n  color: ${(props) => textColor(props.hex)};\n  font-weight: bold;\n`;\n\nconst Ampersand = styled.Text`\n  color: #f3f3f3;\n  font-size: 120px;\n  font-family: Himalaya;\n  line-height: 144px;\n`;\n\nconst Title = styled.Text`\n  font-size: 24px;\n  font-family: 'GT America';\n  font-weight: bold;\n  padding: 4px;\n`;\n\nconst Swatch = ({ name, hex }) => (\n  <SwatchTile name={`Swatch ${name}`} hex={hex}>\n    <SwatchName name=\"Swatch Name\" hex={hex}>\n      {name}\n    </SwatchName>\n    <Ampersand hex={hex}>&</Ampersand>\n  </SwatchTile>\n);\n\nconst Color = {\n  hex: PropTypes.string.isRequired,\n  name: PropTypes.string.isRequired,\n};\n\nSwatch.propTypes = Color;\n\nconst Artboard = styled.View`\n  flex-direction: row;\n  flex-wrap: wrap;\n  width: ${(96 + 8) * 4}px;\n  justify-content: center;\n`;\n\nconst Document = ({ colors }) => (\n  <Artboard name=\"Swatches\">\n    <Title>Max’s Sweaters</Title>\n    {Object.keys(colors).map((color) => (\n      <Swatch name={color} hex={colors[color]} key={color} />\n    ))}\n  </Artboard>\n);\n\nDocument.propTypes = {\n  colors: PropTypes.objectOf(PropTypes.string).isRequired,\n};\n\nexport default () => {\n  const colorList = {\n    Classic: '#96324E',\n    Neue: '#21304E',\n  };\n\n  render(<Document colors={colorList} />, context.document.currentPage());\n};\n"
  },
  {
    "path": "examples/styled-components/webpack.skpm.config.js",
    "content": "const path = require('path');\n\nmodule.exports = (config) => {\n  if (process.env.LOCAL_DEV) {\n    config.resolve = {\n      ...config.resolve,\n      alias: {\n        ...config.resolve.alias,\n        'react-sketchapp': path.resolve(__dirname, '../../'),\n      },\n    };\n  }\n};\n"
  },
  {
    "path": "examples/styleguide/.flowconfig",
    "content": "[ignore]\n\n[include]\n\n[libs]\n\n[options]\n"
  },
  {
    "path": "examples/styleguide/README.md",
    "content": "# Styleguide\n\n## How to use\n\nDownload the example or [clone the repo](http://github.com/airbnb/react-sketchapp):\n\n```bash\ncurl https://codeload.github.com/airbnb/react-sketchapp/tar.gz/master | tar -xz --strip=2 react-sketchapp-master/examples/styleguide\ncd styleguide\n```\n\nInstall the dependencies\n\n```bash\nnpm install\n```\n\nThen, open Sketch and navigate to `Plugins → react-sketchapp: Styleguide`\n\nRun with live reloading in Sketch\n\n```bash\nnpm run render\n```\n\n## The idea behind the example\n\nThe reason we started `react-sketchapp` was to build dynamic styleguides! This is an example showing how to quickly render rich styleguides from JavaScript design system definition. It uses `chroma-js` to dynamically generate color contrast labels.\n\n![examples-styleguide](https://cloud.githubusercontent.com/assets/591643/24778196/2a4ef41a-1ade-11e7-9805-8d974bbfd708.png)\n"
  },
  {
    "path": "examples/styleguide/package.json",
    "content": "{\n  \"name\": \"styleguide\",\n  \"private\": true,\n  \"skpm\": {\n    \"main\": \"styleguide.sketchplugin\",\n    \"manifest\": \"src/manifest.json\"\n  },\n  \"scripts\": {\n    \"build\": \"skpm-build\",\n    \"watch\": \"skpm-build --watch\",\n    \"render\": \"skpm-build --watch --run\",\n    \"render:once\": \"skpm-build --run\",\n    \"postinstall\": \"npm run build && skpm-link\"\n  },\n  \"author\": \"Jon Gold <jon.gold@airbnb.com>\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"chroma-js\": \"^1.2.2\",\n    \"react\": \"^16.3.2\",\n    \"react-sketchapp\": \"^3.0.0\",\n    \"react-test-renderer\": \"^16.3.2\"\n  },\n  \"devDependencies\": {\n    \"@skpm/builder\": \"^0.4.0\"\n  }\n}\n"
  },
  {
    "path": "examples/styleguide/src/components/AccessibilityBadge.js",
    "content": "import * as React from 'react';\nimport Badge from './Badge';\n\nconst AccessibilityBadge = ({ level }) => {\n  let text;\n  switch (true) {\n    case level.aaa:\n      text = 'AAA';\n      break;\n    case level.aa:\n      text = 'AA';\n      break;\n    case level.aaLarge:\n      text = 'AA Large';\n      break;\n    default:\n      text = null;\n  }\n  return text && <Badge>{text}</Badge>;\n};\n\nexport default AccessibilityBadge;\n"
  },
  {
    "path": "examples/styleguide/src/components/Badge.js",
    "content": "import * as React from 'react';\nimport { View, Text } from 'react-sketchapp';\n\nconst Badge = ({ children, filled = false }) => (\n  <View\n    style={{\n      borderRadius: 4,\n      backgroundColor: filled ? '#333' : 'transparent',\n      paddingLeft: 8,\n      paddingRight: 8,\n      borderWidth: 1,\n      borderColor: '#333',\n    }}\n  >\n    <Text\n      style={{\n        color: filled ? '#fff' : '#333',\n      }}\n    >\n      {children}\n    </Text>\n  </View>\n);\n\nexport default Badge;\n"
  },
  {
    "path": "examples/styleguide/src/components/Label.js",
    "content": "import * as React from 'react';\nimport { Text } from 'react-sketchapp';\n\nconst Label = ({ bold, children }) => (\n  <Text\n    style={{\n      color: '#333',\n      fontWeight: bold ? 'bold' : 'normal',\n      fontSize: 16,\n      lineHeight: 24,\n    }}\n  >\n    {children}\n  </Text>\n);\n\nexport default Label;\n"
  },
  {
    "path": "examples/styleguide/src/components/Palette.js",
    "content": "import * as React from 'react';\nimport { View } from 'react-sketchapp';\nimport Swatch from './Swatch';\n\nconst SWATCH_WIDTH = 100;\n\nconst Palette = ({ colors }) => (\n  <View\n    style={{\n      width: (SWATCH_WIDTH + 48) * 4,\n      flexWrap: 'wrap',\n      flexDirection: 'row',\n    }}\n  >\n    {Object.keys(colors).map((name) => (\n      <Swatch key={name} color={colors[name]} name={name} />\n    ))}\n  </View>\n);\n\nexport default Palette;\n"
  },
  {
    "path": "examples/styleguide/src/components/Section.js",
    "content": "import * as React from 'react';\nimport { View } from 'react-sketchapp';\nimport Label from './Label';\n\nconst Section = ({ title, children }) => (\n  <View style={{ marginBottom: 96, flexDirection: 'row' }}>\n    <View style={{ width: 200 }}>\n      <Label bold>{title}</Label>\n    </View>\n    <View>{children}</View>\n  </View>\n);\n\nexport default Section;\n"
  },
  {
    "path": "examples/styleguide/src/components/Swatch.js",
    "content": "import * as React from 'react';\nimport { View } from 'react-sketchapp';\nimport AccessibilityBadge from './AccessibilityBadge';\nimport Label from './Label';\n\nconst SWATCH_WIDTH = 100;\n\nconst Swatch = ({ color, name }) => (\n  <View name={name} style={{ marginBottom: 48, marginRight: 48 }}>\n    <View\n      style={{\n        width: SWATCH_WIDTH,\n        height: SWATCH_WIDTH,\n        backgroundColor: color.hex,\n        borderRadius: 4,\n        marginBottom: 8,\n      }}\n    />\n    <Label bold>{name}</Label>\n    <Label>{color.hex}</Label>\n    <AccessibilityBadge level={color.accessibility} />\n  </View>\n);\n\nexport default Swatch;\n"
  },
  {
    "path": "examples/styleguide/src/components/TypeSpecimen.js",
    "content": "import * as React from 'react';\nimport { View, Text } from 'react-sketchapp';\nimport Label from './Label';\n\nconst TypeSpecimen = ({ name, style }) => (\n  <View name={`TypeSpecimen-${name}`} style={{ flexDirection: 'row', marginBottom: 24 }}>\n    <View style={{ width: 100 }}>\n      <Label>{`${style.fontSize} / ${style.lineHeight}`}</Label>\n    </View>\n    <Text\n      style={{\n        ...style,\n      }}\n    >\n      {name}\n    </Text>\n  </View>\n);\n\nexport default TypeSpecimen;\n"
  },
  {
    "path": "examples/styleguide/src/designSystem.js",
    "content": "import processColor from './processColor';\n\nexport const colors = {\n  Haus: '#F3F4F4',\n  Night: '#333',\n  Sur: '#96DBE4',\n  'Sur a11y': '#24828F',\n  Peach: '#EFADA0',\n  'Peach a11y': '#E37059',\n  Pear: '#93DAAB',\n  'Pear a11y': '#2E854B',\n};\n\nconst typeSizes = [80, 48, 36, 24, 20, 16];\n\nexport const spacing = 16;\n\nconst fontFamilies = {\n  display: 'Helvetica',\n  body: 'Georgia',\n};\n\nconst fontWeights = {\n  regular: 'regular',\n  bold: 'bold',\n};\n\nexport const fonts = {\n  Headline: {\n    color: colors.Night,\n    fontSize: typeSizes[0],\n    fontFamily: fontFamilies.display,\n    fontWeight: fontWeights.bold,\n    lineHeight: 80,\n  },\n  'Title 1': {\n    color: colors.Night,\n    fontSize: typeSizes[2],\n    fontFamily: fontFamilies.display,\n    fontWeight: fontWeights.bold,\n    lineHeight: 48,\n  },\n  'Title 2': {\n    color: colors.Night,\n    fontSize: typeSizes[3],\n    fontFamily: fontFamilies.display,\n    fontWeight: fontWeights.bold,\n    lineHeight: 36,\n  },\n  'Title 3': {\n    color: colors.Night,\n    fontSize: typeSizes[4],\n    fontFamily: fontFamilies.body,\n    fontWeight: fontWeights.regular,\n    lineHeight: 24,\n  },\n  Body: {\n    color: colors.Night,\n    fontSize: typeSizes[5],\n    fontFamily: fontFamilies.body,\n    fontWeight: fontWeights.regular,\n    lineHeight: 24,\n    marginBottom: 24,\n  },\n};\n\nexport default {\n  colors: Object.keys(colors).reduce(\n    (acc, name) => ({\n      ...acc,\n      [name]: processColor(colors[name]),\n    }),\n    {},\n  ),\n  fonts,\n  spacing,\n};\n"
  },
  {
    "path": "examples/styleguide/src/main.js",
    "content": "import * as React from 'react';\nimport { render, TextStyles, View } from 'react-sketchapp';\nimport designSystem from './designSystem';\n\nimport Label from './components/Label';\nimport Palette from './components/Palette';\nimport Section from './components/Section';\nimport TypeSpecimen from './components/TypeSpecimen';\n\nconst Document = ({ system }) => (\n  <View>\n    <View name=\"Intro\" style={{ width: 420, marginBottom: system.spacing * 4 }}>\n      <Label>\n        This is an example react-sketchapp document, showing how to render a styleguide from a data\n        representation of your design system.\n      </Label>\n    </View>\n\n    <Section title=\"Type Styles\">\n      {Object.keys(system.fonts).map((name) => (\n        <TypeSpecimen key={name} name={name} style={TextStyles.get(name)} />\n      ))}\n    </Section>\n\n    <Section title=\"Color Palette\">\n      <Palette colors={system.colors} />\n    </Section>\n  </View>\n);\n\nexport default () => {\n  TextStyles.create(designSystem.fonts, {\n    clearExistingStyles: true,\n  });\n\n  render(<Document system={designSystem} />, context.document.currentPage());\n};\n"
  },
  {
    "path": "examples/styleguide/src/manifest.json",
    "content": "{\n  \"compatibleVersion\": 1,\n  \"bundleVersion\": 1,\n  \"commands\": [\n    {\n      \"name\": \"react-sketchapp: Styleguide\",\n      \"identifier\": \"main\",\n      \"script\": \"./main.js\"\n    }\n  ],\n  \"menu\": {\n    \"isRoot\": true,\n    \"items\": [\n      \"main\"\n    ]\n  }\n}\n"
  },
  {
    "path": "examples/styleguide/src/processColor.js",
    "content": "import chroma from 'chroma-js';\n\nconst minimums = {\n  aa: 4.5,\n  aaLarge: 3,\n  aaa: 7,\n  aaaLarge: 4.5,\n};\n\nexport default (hex) => {\n  const contrast = chroma.contrast(hex, 'white');\n  return {\n    hex,\n    contrast,\n    accessibility: {\n      aa: contrast >= minimums.aa,\n      aaLarge: contrast >= minimums.aaLarge,\n      aaa: contrast >= minimums.aaa,\n      aaaLarge: contrast >= minimums.aaaLarge,\n    },\n  };\n};\n"
  },
  {
    "path": "examples/styleguide/webpack.skpm.config.js",
    "content": "const path = require('path');\n\nmodule.exports = (config) => {\n  if (process.env.LOCAL_DEV) {\n    config.resolve = {\n      ...config.resolve,\n      alias: {\n        ...config.resolve.alias,\n        'react-sketchapp': path.resolve(__dirname, '../../'),\n      },\n    };\n  }\n};\n"
  },
  {
    "path": "examples/symbols/README.md",
    "content": "# Symbol Support\n\n## How to use\n\nDownload the example or [clone the repo](http://github.com/airbnb/react-sketchapp):\n\n```bash\ncurl https://codeload.github.com/airbnb/react-sketchapp/tar.gz/master | tar -xz --strip=2 react-sketchapp-master/examples/symbols\ncd symbols\n```\n\nInstall the dependencies\n\n```bash\nnpm install\n```\n\nThen, open Sketch and navigate to `Plugins → react-sketchapp: Symbol Support`\n\nRun with live reloading in Sketch\n\n```bash\nnpm run render\n```\n\n## The idea behind the example\n\n`react-sketchapp@^0.11.0` introduces an API for creating Sketch symbols — this example shows them in use with React components.\n"
  },
  {
    "path": "examples/symbols/package.json",
    "content": "{\n  \"name\": \"symbols\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"skpm\": {\n    \"main\": \"symbols.sketchplugin\",\n    \"manifest\": \"src/manifest.json\"\n  },\n  \"scripts\": {\n    \"build\": \"skpm-build\",\n    \"watch\": \"skpm-build --watch\",\n    \"render\": \"skpm-build --watch --run\",\n    \"render:once\": \"skpm-build --run\",\n    \"postinstall\": \"npm run build && skpm-link\"\n  },\n  \"author\": \"Jon Gold <jon.gold@airbnb.com>\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@skpm/builder\": \"^0.4.0\"\n  },\n  \"dependencies\": {\n    \"react\": \"^16.3.2\",\n    \"react-sketchapp\": \"^3.0.0\",\n    \"react-test-renderer\": \"^16.3.2\"\n  }\n}\n"
  },
  {
    "path": "examples/symbols/src/manifest.json",
    "content": "{\n\t\"compatibleVersion\": 3,\n\t\"bundleVersion\": 1,\n\t\"commands\": [\n\t\t{\n\t\t\t\"name\": \"react-sketchapp: Symbol Support\",\n\t\t\t\"identifier\": \"main\",\n\t\t\t\"script\": \"./my-command.js\"\n\t\t}\n\t],\n\t\"menu\": {\n\t\t\"isRoot\": true,\n\t\t\"items\": [\n\t\t\t\"main\"\n\t\t]\n\t}\n}\n"
  },
  {
    "path": "examples/symbols/src/my-command.js",
    "content": "import * as React from 'react';\nimport { render, Artboard, Text, View, Image, makeSymbol } from 'react-sketchapp';\n\nconst RedSquare = () => (\n  <View name=\"Square\" style={{ width: 100, height: 100, backgroundColor: 'red' }}>\n    <Text name=\"Red Square Text\">Red Square</Text>\n  </View>\n);\n\nconst RedSquareSym = makeSymbol(RedSquare, 'squares/red');\n\nconst BlueSquare = () => (\n  <View name=\"Square\" style={{ width: 100, height: 100, backgroundColor: 'blue' }}>\n    <Text name=\"Blue Square Text\">Blue Square</Text>\n  </View>\n);\n\nconst BlueSquareSym = makeSymbol(BlueSquare, 'squares/blue');\n\nconst Photo = () => (\n  <Image\n    name=\"Photo\"\n    source=\"https://pbs.twimg.com/profile_images/895665264464764930/7Mb3QtEB_400x400.jpg\"\n    style={{ width: 100, height: 100 }}\n  />\n);\n\nconst PhotoSym = makeSymbol(Photo);\n\nconst Nested = () => (\n  <View name=\"Multi\" style={{ display: 'flex', flexDirection: 'column' }}>\n    <PhotoSym name=\"Photo Instance\" style={{ width: 75, height: 75 }} />\n    <RedSquareSym name=\"Red Square Instance\" style={{ width: 75, height: 75 }} />\n  </View>\n);\n\nconst NestedSym = makeSymbol(Nested);\n\nexport default () => {\n  const Document = () => (\n    <Artboard name=\"Swatches\" style={{ display: 'flex' }}>\n      <NestedSym\n        name=\"Nested Symbol\"\n        overrides={{\n          'Red Square Instance': BlueSquareSym,\n          'Blue Square Text': 'TESTING',\n          Photo: 'https://pbs.twimg.com/profile_images/833785170285178881/loBb32g3.jpg',\n        }}\n      />\n    </Artboard>\n  );\n\n  render(<Document />, context.document.currentPage());\n};\n"
  },
  {
    "path": "examples/symbols/webpack.skpm.config.js",
    "content": "const path = require('path');\n\nmodule.exports = (config) => {\n  if (process.env.LOCAL_DEV) {\n    config.resolve = {\n      ...config.resolve,\n      alias: {\n        ...config.resolve.alias,\n        'react-sketchapp': path.resolve(__dirname, '../../'),\n      },\n    };\n  }\n};\n"
  },
  {
    "path": "examples/timeline-airtable/.eslintrc",
    "content": "{\n  \"env\": {\n    \"browser\": true\n  }\n}\n"
  },
  {
    "path": "examples/timeline-airtable/README.md",
    "content": "# Timeline w/ Airtable\n\n## How to use\n\nDownload the example or [clone the repo](http://github.com/airbnb/react-sketchapp):\n\n```bash\ncurl https://codeload.github.com/airbnb/react-sketchapp/tar.gz/master | tar -xz --strip=2 react-sketchapp-master/examples/timeline-airtable\ncd timeline-airtable\n```\n\nInstall the dependencies\n\n```bash\nnpm install\n```\n\nThen, open Sketch and navigate to `Plugins → react-sketchapp: Timeline w/ Airtable`\n\nRun with live reloading in Sketch\n\n```bash\nnpm run render\n```\n\n## The idea behind the example\n\nSimple timeline feed demonstrates how to retrieve records from Airtable to design with real data\n\n![timeline-airtable](https://cloud.githubusercontent.com/assets/21080/25830456/cdc67bf8-3411-11e7-8998-fdef507ab0d2.png)\n"
  },
  {
    "path": "examples/timeline-airtable/package.json",
    "content": "{\n  \"name\": \"timeline-airtable\",\n  \"private\": true,\n  \"skpm\": {\n    \"main\": \"timeline-airtable.sketchplugin\",\n    \"manifest\": \"src/manifest.json\"\n  },\n  \"scripts\": {\n    \"build\": \"skpm-build\",\n    \"watch\": \"skpm-build --watch\",\n    \"render\": \"skpm-build --watch --run\",\n    \"render:once\": \"skpm-build --run\",\n    \"postinstall\": \"npm run build && skpm-link\"\n  },\n  \"author\": \"David E. Chen <dchen@alumni.cmu.edu>\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"prop-types\": \"^15.5.8\",\n    \"react\": \"^16.3.2\",\n    \"react-sketchapp\": \"^3.0.0\",\n    \"react-test-renderer\": \"^16.3.2\"\n  },\n  \"devDependencies\": {\n    \"@skpm/builder\": \"^0.4.0\"\n  }\n}\n"
  },
  {
    "path": "examples/timeline-airtable/src/main.js",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { render, Artboard, Text, View, StyleSheet } from 'react-sketchapp';\n\nconst API_ENDPOINT_URL =\n  'https://api.airtable.com/v0/appFs7J3WdgHYCDxD/Features?api_key=keyu4dudakWLI0vAh&&sort%5B0%5D%5Bfield%5D=Target+Launch+Date&sort%5B0%5D%5Bdirection%5D=asc';\n\nconst styles = StyleSheet.create({\n  artboard: {\n    backgroundColor: '#F9FDFF',\n  },\n  verticalLine: {\n    width: 3,\n  },\n  dot: {\n    width: 24,\n    height: 24,\n    borderRadius: 12,\n    borderWidth: 2,\n    borderColor: '#46D2B3',\n  },\n  dotCompleted: {\n    backgroundColor: '#46D2B3',\n  },\n  title: {\n    fontSize: 48,\n    fontWeight: 200,\n    color: '#000',\n  },\n  rowContainer: {\n    width: 800,\n    flexDirection: 'row',\n    flex: 1,\n    paddingLeft: 30,\n    paddingRight: 30,\n  },\n  rowDescription: {\n    fontSize: 16,\n    width: 400,\n  },\n  rowLeftArea: {\n    width: 99, // odd number to avoid antialiasing\n    alignItems: 'center',\n    height: 150,\n  },\n  rowDate: {\n    fontSize: 10,\n    color: '#46D2B3',\n  },\n  rowTitle: {\n    fontSize: 20,\n  },\n});\n\nconst VerticalLine = ({ height = 1, color = '#46D2B3' }) => (\n  <View style={[styles.verticalLine, { flex: height, backgroundColor: color }]} />\n);\n\nVerticalLine.propTypes = {\n  height: PropTypes.number,\n  color: PropTypes.string,\n};\n\nconst Header = ({ title }) => (\n  <View style={[styles.rowContainer, { backgroundColor: '#fff' }]}>\n    <View style={styles.rowLeftArea}>\n      <VerticalLine />\n    </View>\n    <View>\n      <Text style={styles.title}>{title}</Text>\n    </View>\n  </View>\n);\n\nHeader.propTypes = {\n  title: PropTypes.string,\n};\n\nconst Footer = () => (\n  <View style={styles.rowContainer}>\n    <View style={styles.rowLeftArea}>\n      <VerticalLine height={40} />\n    </View>\n  </View>\n);\n\nconst Dot = ({ completed }) => (\n  <View name=\"Dot\" style={[styles.dot, completed && styles.dotCompleted]} />\n);\n\nDot.propTypes = {\n  completed: PropTypes.bool,\n};\n\nconst Row = ({ title, description, completed, date, status }) => (\n  <View style={styles.rowContainer}>\n    <View name=\"Row Left\" style={styles.rowLeftArea}>\n      <VerticalLine />\n      <Dot completed={completed} />\n      <VerticalLine height={4} />\n    </View>\n    <View name=\"Row Body\" style={{ opacity: completed ? 1 : 0.5 }}>\n      <Text name=\"Row Date\" style={styles.rowDate}>\n        {`${status} on ${date}`}\n      </Text>\n      <Text name=\"Row Title\" style={styles.rowTitle}>\n        {title}\n      </Text>\n      <Text name=\"Row Description\" style={styles.rowDescription}>\n        {description}\n      </Text>\n    </View>\n  </View>\n);\n\nRow.propTypes = {\n  title: PropTypes.string,\n  description: PropTypes.string,\n  completed: PropTypes.bool,\n  date: PropTypes.string,\n  status: PropTypes.string,\n};\n\nconst Timeline = (props) => (\n  <Artboard style={styles.artboard}>\n    <Header title=\"Product Timeline\" />\n    {props.data.records.map(({ id, fields }) => (\n      <Row\n        key={id}\n        title={fields.Feature}\n        description={fields['Feature Description']}\n        status={fields['Launched?'] ? 'Launched' : fields['Feature Status']}\n        completed={fields['Launched?']}\n        date={fields['Target Launch Date']}\n      />\n    ))}\n    <Footer />\n  </Artboard>\n);\n\nTimeline.propTypes = {\n  data: PropTypes.shape({\n    records: PropTypes.array,\n  }),\n};\n\nexport default () => {\n  fetch(API_ENDPOINT_URL)\n    .then((res) => res.json())\n    .then((data) => {\n      render(<Timeline data={data} />, context.document.currentPage());\n    })\n    .catch((e) => console.error(e));\n};\n"
  },
  {
    "path": "examples/timeline-airtable/src/manifest.json",
    "content": "{\n  \"compatibleVersion\": 1,\n  \"bundleVersion\": 1,\n  \"commands\": [\n    {\n      \"name\": \"react-sketchapp: Timeline w/ Airtable\",\n      \"identifier\": \"main\",\n      \"script\": \"./main.js\"\n    }\n  ],\n  \"menu\": {\n    \"isRoot\": true,\n    \"items\": [\n      \"main\"\n    ]\n  }\n}\n"
  },
  {
    "path": "examples/timeline-airtable/webpack.skpm.config.js",
    "content": "const path = require('path');\n\nmodule.exports = (config) => {\n  if (process.env.LOCAL_DEV) {\n    config.resolve = {\n      ...config.resolve,\n      alias: {\n        ...config.resolve.alias,\n        'react-sketchapp': path.resolve(__dirname, '../../'),\n      },\n    };\n  }\n};\n"
  },
  {
    "path": "jest.config.js",
    "content": "module.exports = {\n  preset: 'ts-jest',\n  testEnvironment: 'node',\n  testRegex: '/__tests__/jest/.*\\\\.(j|t)sx?$',\n  testPathIgnorePatterns: [\n    '/node_modules/',\n    '<rootDir>/_book',\n    '<rootDir>/lib',\n    '<rootDir>/scratch',\n    '<rootDir>/template',\n    '<rootDir>/src',\n    '<rootDir>/docs',\n  ],\n  globals: {\n    'ts-jest': {\n      isolatedModules: true,\n    },\n  },\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"react-sketchapp\",\n  \"version\": \"3.2.6\",\n  \"description\": \"A React renderer for Sketch.app\",\n  \"sideEffects\": false,\n  \"main\": \"lib/index.js\",\n  \"module\": \"lib/module/index.js\",\n  \"types\": \"lib/index.d.ts\",\n  \"license\": \"MIT\",\n  \"author\": \"Jon Gold <jon.gold@airbnb.com> (http://jon.gold)\",\n  \"contributors\": [\n    \"Ben Wilkins <ben.wilkins@airbnb.com>\",\n    \"Leland Richardson <leland.richardson@airbnb.com>\",\n    \"Mathieu Dutour <mathieu@dutour.me>\",\n    \"Jarid Margolin <jaridmargolin@gmail.com>\"\n  ],\n  \"pre-commit\": [\n    \"lint-staged\"\n  ],\n  \"scripts\": {\n    \"build\": \"run-s clean && run-p build:*\",\n    \"build:main\": \"tsc -p tsconfig.json\",\n    \"build:module\": \"tsc -p tsconfig.module.json\",\n    \"fix\": \"run-s fix:*\",\n    \"fix:prettier\": \"prettier \\\"src/**/*.ts\\\" --write\",\n    \"clean\": \"trash lib\",\n    \"docs:clean\": \"trash _book\",\n    \"docs:prepare\": \"gitbook install\",\n    \"docs:build\": \"npm run docs:prepare && gitbook build\",\n    \"docs:watch\": \"npm run docs:prepare && gitbook serve\",\n    \"docs:publish\": \"npm run docs:clean && npm run docs:build && cd _book && git init && git commit --allow-empty -m 'update book' && git fetch https://github.com/airbnb/react-sketchapp gh-pages && git checkout -b gh-pages && git add . && git commit -am 'update book' && git push https://github.com/airbnb/react-sketchapp gh-pages --force\",\n    \"lint-staged\": \"lint-staged\",\n    \"prepublishOnly\": \"npm run clean && npm run test:ci && npm run build\",\n    \"prettier:base\": \"prettier --write\",\n    \"prettify\": \"npm run prettier:base \\\"src/**/*.(j|t)sx?\\\" \\\"examples/**/*.(j|t)sx?\\\" \\\"__tests__/**/*.(j|t)sx?\\\" \\\"docs/**/*.md\\\"\",\n    \"test\": \"npm run test:unit && npm run test:e2e\",\n    \"test:unit\": \"jest --config jest.config.js --no-watchman\",\n    \"test:ci\": \"npm run test:unit -- --runInBand\",\n    \"test:e2e\": \"skpm-test\",\n    \"test:update\": \"npm run test -- --updateSnapshot\",\n    \"test:e2e:watch\": \"npm run test:e2e -- --watch\",\n    \"watch\": \"run-s clean build:main && run-p \\\"build:main -- -w\\\" \\\"test:unit -- --watch\\\"\"\n  },\n  \"dependencies\": {\n    \"@lona/svg-model\": \"^2.0.0\",\n    \"@sketch-hq/sketch-file-format-ts\": \"4.0.3\",\n    \"airbnb-prop-types\": \"^2.15.0\",\n    \"error-stack-parser\": \"^2.0.6\",\n    \"invariant\": \"^2.2.2\",\n    \"js-sha1\": \"^0.6.0\",\n    \"murmur2js\": \"^1.0.0\",\n    \"node-sketch-bridge\": \"^0.2.0\",\n    \"normalize-css-color\": \"^1.0.1\",\n    \"pegjs\": \"^0.10.0\",\n    \"prop-types\": \"^15.7.2\",\n    \"seedrandom\": \"^3.0.5\",\n    \"yoga-layout-prebuilt\": \"^1.9.5\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"*\",\n    \"react-test-renderer\": \"*\"\n  },\n  \"keywords\": [\n    \"sketch\",\n    \"sketchapp\",\n    \"react\",\n    \"reactjs\",\n    \"renderer\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/airbnb/react-sketchapp\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/airbnb/react-sketchapp/issues\"\n  },\n  \"homepage\": \"https://github.com/airbnb/react-sketchapp\",\n  \"lint-staged\": {\n    \"*.{js,jsx,ts,tsx,md}\": \"npm run prettier:base\"\n  },\n  \"devDependencies\": {\n    \"@skpm/babel-preset\": \"^0.2.1\",\n    \"@skpm/test-runner\": \"^0.4.1\",\n    \"@types/airbnb-prop-types\": \"^2.13.1\",\n    \"@types/invariant\": \"^2.2.31\",\n    \"@types/jest\": \"^25.2.1\",\n    \"@types/node\": \"^13.13.2\",\n    \"@types/pegjs\": \"^0.10.1\",\n    \"@types/react\": \"^16.9.34\",\n    \"@types/react-test-renderer\": \"^16.9.2\",\n    \"@types/seedrandom\": \"^2.4.28\",\n    \"gitbook-cli\": \"^2.3.0\",\n    \"gitbook-plugin-anchorjs\": \"^2.1.0\",\n    \"gitbook-plugin-codeblock-disable-glossary\": \"0.0.1\",\n    \"gitbook-plugin-edit-link\": \"^2.0.2\",\n    \"gitbook-plugin-github\": \"^2.0.0\",\n    \"gitbook-plugin-prism\": \"^2.3.0\",\n    \"jest\": \"^25.4.0\",\n    \"jest-cli\": \"^25.4.0\",\n    \"lint-staged\": \"^10.1.7\",\n    \"npm-run-all\": \"^4.1.5\",\n    \"pre-commit\": \"^1.2.2\",\n    \"prettier\": \"^2.0.5\",\n    \"react\": \"^16.13.1\",\n    \"react-test-renderer\": \"^16.13.1\",\n    \"sketchapp-json-flow-types\": \"^0.3.6\",\n    \"trash-cli\": \"^3.0.0\",\n    \"ts-jest\": \"^25.4.0\",\n    \"typescript\": \"^3.8.3\"\n  },\n  \"skpm\": {\n    \"test\": {\n      \"testRegex\": \"/__tests__/skpm/.*\\\\.jsx?$\"\n    }\n  }\n}\n"
  },
  {
    "path": "prettier.config.js",
    "content": "module.exports = {\n  singleQuote: true,\n  trailingComma: 'all',\n  printWidth: 100,\n  proseWrap: 'never',\n};\n"
  },
  {
    "path": "src/Platform.ts",
    "content": "import { getSketchVersion } from './utils/getSketchVersion';\n\nexport const Platform = {\n  OS: 'sketch',\n  Version: getSketchVersion(),\n  select: (obj: { sketch: any }) => obj.sketch,\n};\n"
  },
  {
    "path": "src/buildTree.ts",
    "content": "import * as TestRenderer from 'react-test-renderer';\nimport yoga from 'yoga-layout-prebuilt';\nimport { Context } from './utils/Context';\nimport { TreeNode, TextNode, PlatformBridge } from './types';\nimport { hasAnyDefined } from './utils/hasAnyDefined';\nimport { pick } from './utils/pick';\nimport { computeYogaTree } from './jsonUtils/computeYogaTree';\nimport { computeTextTree } from './jsonUtils/computeTextTree';\nimport { INHERITABLE_FONT_STYLES } from './utils/constants';\nimport { zIndex } from './utils/zIndex';\n\nexport const reactTreeToFlexTree = (\n  node: TestRenderer.ReactTestRendererNode,\n  yogaNode: yoga.YogaNode,\n  context: Context,\n): TreeNode => {\n  let textNodes: TextNode[] = [];\n  let textStyle = context.getInheritedStyles();\n\n  let newChildren: (string | TreeNode<any>)[] = [];\n\n  let style: any;\n  let type: string;\n\n  if (typeof node === 'string') {\n    textNodes = computeTextTree(node, context);\n    type = 'sketch_text';\n  } else {\n    style = node.props && node.props.style ? node.props.style : {};\n    type = node.type || 'sketch_text';\n\n    if (type === 'sketch_svg' && node.children) {\n      // @ts-ignore\n      newChildren = node.children;\n    } else if (type === 'sketch_text') {\n      // If current node is a Text node, add text styles to Context to pass down to\n      // child nodes.\n      if (node.props && node.props.style && hasAnyDefined(style, INHERITABLE_FONT_STYLES)) {\n        const inheritableStyles: any = pick(style, INHERITABLE_FONT_STYLES);\n        inheritableStyles.flexDirection = 'row';\n        context.addInheritableStyles(inheritableStyles);\n        textStyle = {\n          ...context.getInheritedStyles(),\n          ...inheritableStyles,\n        };\n      }\n\n      // Compute Text Children\n      textNodes = computeTextTree(node, context);\n    } else if (node.children && node.children.length > 0) {\n      // Recursion reverses the render stacking order\n      // but that's actually fine because Sketch renders the first on top\n\n      // Calculates zIndex order to match yoga\n      const children = zIndex(node.children);\n\n      for (let index = 0; index < children.length; index += 1) {\n        const childComponent = children[index];\n\n        const childNode = yogaNode.getChild(index);\n\n        const renderedChildComponent = reactTreeToFlexTree(\n          childComponent,\n          childNode,\n          context.forChildren(),\n        );\n        newChildren.push(renderedChildComponent);\n      }\n    }\n  }\n\n  return {\n    type,\n    style,\n    textStyle,\n    layout: {\n      left: yogaNode.getComputedLeft(),\n      right: yogaNode.getComputedRight(),\n      top: yogaNode.getComputedTop(),\n      bottom: yogaNode.getComputedBottom(),\n      width: yogaNode.getComputedWidth(),\n      height: yogaNode.getComputedHeight(),\n    },\n    props: {\n      ...(typeof node !== 'string' ? node.props : {}),\n      textNodes,\n    },\n    children: newChildren,\n  };\n};\n\nexport const buildTree = (bridge: PlatformBridge) => (element: React.ReactElement) => {\n  let renderer: TestRenderer.ReactTestRenderer | undefined;\n\n  if (typeof TestRenderer.act !== 'undefined') {\n    TestRenderer.act(() => {\n      // synchronous callback\n      renderer = TestRenderer.create(element);\n    });\n  } else {\n    renderer = TestRenderer.create(element);\n  }\n\n  if (!renderer) {\n    throw new Error('Cannot access react renderer');\n  }\n\n  const json = renderer.toJSON();\n  if (!json) {\n    throw new Error('Cannot render react element');\n  }\n  const yogaNode = computeYogaTree(bridge)(json, new Context());\n  yogaNode.calculateLayout(undefined, undefined, yoga.DIRECTION_LTR);\n  const tree = reactTreeToFlexTree(json, yogaNode, new Context());\n\n  return tree;\n};\n"
  },
  {
    "path": "src/components/Artboard.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { or } from 'airbnb-prop-types';\nimport { StyleSheet } from '../stylesheet';\nimport { ViewStylePropTypes } from './ViewStylePropTypes';\nimport { ArtboardProvider } from '../context';\n\nconst ViewportPropTypes = {\n  name: PropTypes.string,\n  width: PropTypes.number,\n  height: PropTypes.number,\n  scale: PropTypes.number,\n  fontScale: PropTypes.number,\n};\n\nexport const ArtboardPropTypes = {\n  style: or([PropTypes.shape(ViewStylePropTypes), PropTypes.number]),\n  name: PropTypes.string,\n  isHome: PropTypes.bool,\n  children: PropTypes.node,\n  viewport: PropTypes.shape(ViewportPropTypes),\n};\n\nexport type Props = PropTypes.InferProps<typeof ArtboardPropTypes>;\n\nexport class Artboard extends React.Component<Props> {\n  static propTypes = ArtboardPropTypes;\n\n  static defaultProps = {\n    name: 'Artboard',\n  };\n\n  render() {\n    const style = StyleSheet.flatten(this.props.style);\n    return (\n      <ArtboardProvider viewport={this.props.viewport} style={style}>\n        <sketch_artboard\n          style={style}\n          name={this.props.name}\n          viewport={this.props.viewport}\n          isHome={this.props.isHome}\n        >\n          {this.props.children}\n        </sketch_artboard>\n      </ArtboardProvider>\n    );\n  }\n}\n"
  },
  {
    "path": "src/components/Document.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\n\nexport const DocumentPropTypes = {\n  children: PropTypes.node,\n};\n\ntype Props = PropTypes.InferProps<typeof DocumentPropTypes>;\n\nexport class Document extends React.Component<Props> {\n  static propTypes = {\n    children: PropTypes.node,\n  };\n\n  render() {\n    return <sketch_document>{this.props.children}</sketch_document>;\n  }\n}\n"
  },
  {
    "path": "src/components/Image.tsx",
    "content": "import * as React from 'react';\nimport { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport * as PropTypes from 'prop-types';\nimport { or } from 'airbnb-prop-types';\nimport { StyleSheet } from '../stylesheet';\nimport { ResizeModePropTypes } from './ResizeModePropTypes';\nimport { ImageStylePropTypes } from './ImageStylePropTypes';\nimport { ViewPropTypes } from './View';\n\nconst ImageURISourcePropType = PropTypes.shape({\n  uri: PropTypes.string.isRequired,\n  height: PropTypes.number,\n  width: PropTypes.number,\n  // bundle: PropTypes.string,\n  // method: PropTypes.string,\n  // headers: PropTypes.objectOf(PropTypes.string),\n  // body: PropTypes.string,\n  // cache: PropTypes.oneOf(['default', 'reload', 'force-cache', 'only-if-cached']),\n  // scale: PropTypes.number,\n});\n\nexport const ImageSourcePropType = PropTypes.oneOfType([\n  ImageURISourcePropType,\n  // PropTypes.arrayOf(ImageURISourcePropType), // TODO: handle me\n  PropTypes.string,\n]);\n\nconst ResizeModes: { [key: string]: FileFormat.PatternFillType } = {\n  contain: 3,\n  cover: 1,\n  stretch: 2,\n  center: 1, // TODO(gold): implement ResizeModes.center\n  repeat: 0,\n  none: 1,\n};\n\nexport const ImagePropTypes = {\n  ...ViewPropTypes,\n  style: or([PropTypes.shape(ImageStylePropTypes), PropTypes.number]),\n  defaultSource: ImageSourcePropType,\n  resizeMode: ResizeModePropTypes,\n  source: ImageSourcePropType,\n};\n\nexport type Props = PropTypes.InferProps<typeof ImagePropTypes>;\n\nexport class Image extends React.Component<Props> {\n  static propTypes = ImagePropTypes;\n\n  static defaultProps = {\n    name: 'Image',\n  };\n\n  render() {\n    const { children, source, defaultSource, resizeMode, name, resizingConstraint } = this.props;\n\n    let style = StyleSheet.flatten(this.props.style) || {};\n\n    const sketchResizeMode = ResizeModes[resizeMode || (style && style.resizeMode) || 'cover'];\n\n    if (source && typeof source !== 'string') {\n      style = {\n        height: source.height,\n        width: source.width,\n        ...style,\n      };\n    }\n\n    return (\n      <sketch_image\n        style={style}\n        source={source || defaultSource}\n        name={name}\n        resizeMode={sketchResizeMode}\n        resizingConstraint={resizingConstraint}\n      >\n        {children}\n      </sketch_image>\n    );\n  }\n}\n"
  },
  {
    "path": "src/components/ImageStylePropTypes.ts",
    "content": "import { ViewStylePropTypes } from './ViewStylePropTypes';\nimport { ResizeModePropTypes } from './ResizeModePropTypes';\n\nexport const ImageStylePropTypes = {\n  ...ViewStylePropTypes,\n  resizeMode: ResizeModePropTypes,\n};\n"
  },
  {
    "path": "src/components/Page.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { or } from 'airbnb-prop-types';\nimport { StyleSheet } from '../stylesheet';\nimport { PageStylePropTypes } from './PageStylePropTypes';\n\nexport const PagePropTypes = {\n  name: PropTypes.string,\n  children: PropTypes.node,\n  style: or([PropTypes.shape(PageStylePropTypes), PropTypes.number]),\n};\n\ntype Props = PropTypes.InferProps<typeof PagePropTypes>;\n\nexport class Page extends React.Component<Props> {\n  static propTypes = PagePropTypes;\n\n  render() {\n    const { name, children, style, ...otherProps } = this.props;\n    const _name = name === 'Symbols' ? 'Symbols (renamed to avoid conflict)' : name;\n    const _style = StyleSheet.flatten(style);\n\n    return (\n      <sketch_page name={_name} style={_style} {...otherProps}>\n        {children}\n      </sketch_page>\n    );\n  }\n}\n"
  },
  {
    "path": "src/components/PageStylePropTypes.ts",
    "content": "export const PageStylePropTypes = {};\n"
  },
  {
    "path": "src/components/RedBox.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport ErrorStackParser from 'error-stack-parser';\nimport { Text } from './Text';\nimport { View } from './View';\n\ntype StackFrame = {\n  isConstrutor?: boolean;\n  isEval?: boolean;\n  isNative?: boolean;\n  isTopLevel?: boolean;\n  columnNumber?: number;\n  lineNumber?: number;\n  fileName?: string;\n  functionName?: string;\n  source?: string;\n  args?: any[];\n  evalOrigin?: StackFrame;\n};\n\nconst styles = {\n  redbox: {\n    padding: 10,\n    width: 480,\n    backgroundColor: 'rgb(204, 0, 0)',\n  },\n  frame: {},\n  message: {\n    fontWeight: 'bold',\n    fontSize: 16,\n    lineHeight: 16 * 1.2,\n    color: 'white',\n  },\n  stack: {\n    fontFamily: 'Monaco',\n    marginTop: 20,\n    color: 'white',\n  },\n};\n\nexport const ErrorBoxPropTypes = {\n  error: PropTypes.oneOfType([PropTypes.instanceOf(Error), PropTypes.string]).isRequired,\n  // filename: PropTypes.string,\n  // editorScheme: PropTypes.string,\n  // useLines: PropTypes.bool,\n  // useColumns: PropTypes.bool,\n};\n\ntype Props = PropTypes.InferProps<typeof ErrorBoxPropTypes>;\n\nexport class RedBox extends React.Component<Props> {\n  static propTypes = ErrorBoxPropTypes;\n\n  static defaultProps = {\n    useLines: true,\n    useColumns: true,\n  };\n\n  renderFrames(frames: Array<StackFrame>) {\n    return frames.map((f, index) => (\n      <Text key={index} style={styles.stack}>\n        {f.functionName}\n      </Text>\n    ));\n  }\n\n  render() {\n    const { error } = this.props;\n\n    if (typeof error === 'string') {\n      return (\n        <View name=\"RedBox\" style={styles.redbox}>\n          <Text name=\"Message\" style={styles.message}>{`Error: ${error}`}</Text>\n        </View>\n      );\n    }\n\n    let frames: ErrorStackParser.StackFrame[] | undefined;\n    let parseError: Error | undefined;\n\n    let frameChildren: JSX.Element[] | JSX.Element | undefined;\n\n    try {\n      frames = ErrorStackParser.parse(error);\n    } catch (e) {\n      parseError = new Error('Failed to parse stack trace. Stack trace information unavailable.');\n    }\n\n    if (parseError) {\n      frameChildren = (\n        <View style={styles.frame} key={0}>\n          <View>{parseError.message}</View>\n        </View>\n      );\n    }\n\n    if (frames) {\n      frameChildren = this.renderFrames(frames);\n    }\n\n    return (\n      <View name=\"RedBox\" style={styles.redbox}>\n        <Text name=\"Message\" style={styles.message}>\n          {`${error.name}: ${error.message}`}\n        </Text>\n        <View name=\"Frames\" style={styles.stack}>\n          {frameChildren}\n        </View>\n      </View>\n    );\n  }\n}\n"
  },
  {
    "path": "src/components/ResizeModePropTypes.ts",
    "content": "import * as PropTypes from 'prop-types';\n\nexport const ResizeModePropTypes = PropTypes.oneOf([\n  'contain',\n  'cover',\n  'stretch',\n  'center',\n  'repeat',\n  'none',\n]);\n"
  },
  {
    "path": "src/components/ResizingConstraintPropTypes.ts",
    "content": "import * as PropTypes from 'prop-types';\n\nexport const ResizingConstraintPropTypes = {\n  top: PropTypes.bool,\n  right: PropTypes.bool,\n  bottom: PropTypes.bool,\n  left: PropTypes.bool,\n  fixedHeight: PropTypes.bool,\n  fixedWidth: PropTypes.bool,\n};\n"
  },
  {
    "path": "src/components/ShadowsPropTypes.ts",
    "content": "import * as PropTypes from 'prop-types';\n\nexport const ShadowsPropTypes = {\n  shadowColor: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n  shadowOffset: PropTypes.shape({\n    width: PropTypes.number,\n    height: PropTypes.number,\n  }),\n  shadowOpacity: PropTypes.number,\n  shadowRadius: PropTypes.number,\n  shadowSpread: PropTypes.number,\n  shadowInner: PropTypes.bool,\n};\n"
  },
  {
    "path": "src/components/Svg/Circle.tsx",
    "content": "import * as React from 'react';\nimport { pathProps, numberProp } from './props';\nimport * as PropTypes from 'prop-types';\n\nconst propTypes = {\n  ...pathProps,\n  cx: numberProp.isRequired,\n  cy: numberProp.isRequired,\n  r: numberProp.isRequired,\n};\n\ntype Props = PropTypes.InferProps<typeof propTypes>;\n\nexport class Circle extends React.Component<Props> {\n  static propTypes = propTypes;\n\n  static defaultProps = {\n    cx: 0,\n    cy: 0,\n    r: 0,\n  };\n\n  render() {\n    const { children, ...rest } = this.props;\n    return <svg_circle {...rest}>{children}</svg_circle>;\n  }\n}\n"
  },
  {
    "path": "src/components/Svg/ClipPath.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\n\nconst propTypes = {\n  id: PropTypes.string.isRequired,\n  children: PropTypes.node,\n};\n\ntype Props = PropTypes.InferProps<typeof propTypes>;\n\nexport class ClipPath extends React.Component<Props> {\n  static propTypes = propTypes;\n\n  render() {\n    return <svg_clipPath id={this.props.id}>{this.props.children}</svg_clipPath>;\n  }\n}\n"
  },
  {
    "path": "src/components/Svg/Defs.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\n\nconst propTypes = {\n  children: PropTypes.node.isRequired,\n};\n\ntype Props = PropTypes.InferProps<typeof propTypes>;\n\nexport class Defs extends React.Component<Props> {\n  static propTypes = propTypes;\n\n  render() {\n    return <svg_defs>{this.props.children}</svg_defs>;\n  }\n}\n"
  },
  {
    "path": "src/components/Svg/Ellipse.tsx",
    "content": "import * as React from 'react';\nimport { pathProps, numberProp } from './props';\nimport * as PropTypes from 'prop-types';\n\nconst propTypes = {\n  ...pathProps,\n  cx: numberProp.isRequired,\n  cy: numberProp.isRequired,\n  rx: numberProp.isRequired,\n  ry: numberProp.isRequired,\n};\n\ntype Props = PropTypes.InferProps<typeof propTypes>;\n\nexport class Ellipse extends React.Component<Props> {\n  static propTypes = propTypes;\n\n  static defaultProps = {\n    cx: 0,\n    cy: 0,\n    rx: 0,\n    ry: 0,\n  };\n\n  render() {\n    const { children, ...rest } = this.props;\n    return <svg_ellipse {...rest}>{children}</svg_ellipse>;\n  }\n}\n"
  },
  {
    "path": "src/components/Svg/G.tsx",
    "content": "import * as React from 'react';\nimport { pathProps, fontProps } from './props';\nimport * as PropTypes from 'prop-types';\n\nconst propTypes = {\n  ...pathProps,\n  ...fontProps,\n};\n\ntype Props = PropTypes.InferProps<typeof propTypes>;\n\nexport class G extends React.Component<Props> {\n  static propTypes = propTypes;\n\n  render() {\n    const { children, ...rest } = this.props;\n\n    return <svg_g {...rest}>{children}</svg_g>;\n  }\n}\n"
  },
  {
    "path": "src/components/Svg/Image.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { ImageSourcePropType } from '../Image';\nimport { numberProp } from './props';\n\nconst propTypes = {\n  x: numberProp,\n  y: numberProp,\n  width: numberProp.isRequired,\n  height: numberProp.isRequired,\n  href: ImageSourcePropType,\n  preserveAspectRatio: PropTypes.string,\n  children: PropTypes.node,\n};\n\ntype Props = PropTypes.InferProps<typeof propTypes>;\n\nexport class SVGImage extends React.Component<Props> {\n  static propTypes = propTypes;\n\n  static defaultProps = {\n    x: 0,\n    y: 0,\n    width: 0,\n    height: 0,\n    preserveAspectRatio: 'xMidYMid meet',\n  };\n\n  render() {\n    const { children, ...rest } = this.props;\n    return <svg_image {...rest}>{children}</svg_image>;\n  }\n}\n"
  },
  {
    "path": "src/components/Svg/Line.tsx",
    "content": "import * as React from 'react';\nimport { pathProps, numberProp } from './props';\nimport * as PropTypes from 'prop-types';\n\nconst propTypes = {\n  ...pathProps,\n  x1: numberProp.isRequired,\n  x2: numberProp.isRequired,\n  y1: numberProp.isRequired,\n  y2: numberProp.isRequired,\n};\n\ntype Props = PropTypes.InferProps<typeof propTypes>;\n\nexport class Line extends React.Component<Props> {\n  static propTypes = propTypes;\n\n  static defaultProps = {\n    x1: 0,\n    y1: 0,\n    x2: 0,\n    y2: 0,\n  };\n\n  render() {\n    const { children, ...rest } = this.props;\n    return <svg_line {...rest}>{children}</svg_line>;\n  }\n}\n"
  },
  {
    "path": "src/components/Svg/LinearGradient.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { numberProp } from './props';\n\nconst propTypes = {\n  x1: numberProp.isRequired,\n  x2: numberProp.isRequired,\n  y1: numberProp.isRequired,\n  y2: numberProp.isRequired,\n  gradientUnits: PropTypes.oneOf(['objectBoundingBox', 'userSpaceOnUse']),\n  id: PropTypes.string.isRequired,\n  children: PropTypes.node,\n};\n\ntype Props = PropTypes.InferProps<typeof propTypes>;\n\nexport class LinearGradient extends React.Component<Props> {\n  static propTypes = propTypes;\n\n  static defaultProps = {\n    x1: '0%',\n    y1: '0%',\n    x2: '100%',\n    y2: '0%',\n  };\n\n  render() {\n    const { children, ...rest } = this.props;\n    return <svg_linearGradient {...rest}>{children}</svg_linearGradient>;\n  }\n}\n"
  },
  {
    "path": "src/components/Svg/Path.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { pathProps } from './props';\n\nconst propTypes = {\n  ...pathProps,\n  d: PropTypes.string.isRequired,\n};\n\ntype Props = PropTypes.InferProps<typeof propTypes>;\n\nexport class Path extends React.Component<Props> {\n  static propTypes = propTypes;\n\n  render() {\n    const { children, ...rest } = this.props;\n    return <svg_path {...rest}>{children}</svg_path>;\n  }\n}\n"
  },
  {
    "path": "src/components/Svg/Pattern.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { numberProp } from './props';\n\nconst propTypes = {\n  x1: numberProp,\n  x2: numberProp,\n  y1: numberProp,\n  y2: numberProp,\n  patternTransform: PropTypes.string,\n  patternUnits: PropTypes.oneOf(['userSpaceOnUse', 'objectBoundingBox']),\n  patternContentUnits: PropTypes.oneOf(['userSpaceOnUse', 'objectBoundingBox']),\n  children: PropTypes.node,\n};\n\ntype Props = PropTypes.InferProps<typeof propTypes>;\n\nexport class Pattern extends React.Component<Props> {\n  static propTypes = propTypes;\n\n  render() {\n    const { children, ...rest } = this.props;\n    return <svg_pattern {...rest}>{children}</svg_pattern>;\n  }\n}\n"
  },
  {
    "path": "src/components/Svg/Polygon.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { pathProps } from './props';\n\nconst propTypes = {\n  ...pathProps,\n  points: PropTypes.string.isRequired,\n};\n\ntype Props = PropTypes.InferProps<typeof propTypes>;\n\nexport class Polygon extends React.Component<Props> {\n  static displayName = 'Polygon';\n\n  static propTypes = propTypes;\n\n  static defaultProps = {\n    points: '',\n  };\n\n  render() {\n    const { children, ...rest } = this.props;\n    return <svg_polygon {...rest}>{children}</svg_polygon>;\n  }\n}\n"
  },
  {
    "path": "src/components/Svg/Polyline.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { pathProps } from './props';\n\nconst propTypes = {\n  ...pathProps,\n  points: PropTypes.string.isRequired,\n};\n\ntype Props = PropTypes.InferProps<typeof propTypes>;\n\nexport class Polyline extends React.Component<Props> {\n  static propTypes = propTypes;\n\n  static defaultProps = {\n    points: '',\n  };\n\n  render() {\n    const { children, ...rest } = this.props;\n    return <svg_polyline {...rest}>{children}</svg_polyline>;\n  }\n}\n"
  },
  {
    "path": "src/components/Svg/RadialGradient.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { numberProp } from './props';\n\nconst propTypes = {\n  fx: numberProp.isRequired,\n  fy: numberProp.isRequired,\n  rx: numberProp,\n  ry: numberProp,\n  cx: numberProp.isRequired,\n  cy: numberProp.isRequired,\n  r: numberProp,\n  gradientUnits: PropTypes.oneOf(['objectBoundingBox', 'userSpaceOnUse']),\n  id: PropTypes.string.isRequired,\n  children: PropTypes.node,\n};\n\ntype Props = PropTypes.InferProps<typeof propTypes>;\n\nexport class RadialGradient extends React.Component<Props> {\n  static propTypes = propTypes;\n\n  static defaultProps = {\n    fx: '50%',\n    fy: '50%',\n    cx: '50%',\n    cy: '50%',\n    r: '50%',\n  };\n\n  render() {\n    const { children, ...rest } = this.props;\n    return <svg_radialGradient {...rest}>{children}</svg_radialGradient>;\n  }\n}\n"
  },
  {
    "path": "src/components/Svg/Rect.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { pathProps, numberProp } from './props';\n\nconst propTypes = {\n  ...pathProps,\n  x: numberProp.isRequired,\n  y: numberProp.isRequired,\n  width: numberProp.isRequired,\n  height: numberProp.isRequired,\n  rx: numberProp,\n  ry: numberProp,\n};\n\ntype Props = PropTypes.InferProps<typeof propTypes>;\n\nexport class Rect extends React.Component<Props> {\n  static propTypes = propTypes;\n\n  static defaultProps = {\n    x: 0,\n    y: 0,\n    width: 0,\n    height: 0,\n    rx: 0,\n    ry: 0,\n  };\n\n  render() {\n    const { children, ...rest } = this.props;\n    return <svg_rect {...rest}>{children}</svg_rect>;\n  }\n}\n"
  },
  {
    "path": "src/components/Svg/Stop.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { numberProp } from './props';\n\nconst propTypes = {\n  stopColor: PropTypes.string,\n  stopOpacity: numberProp,\n  children: PropTypes.node,\n};\n\ntype Props = PropTypes.InferProps<typeof propTypes>;\n\nexport class Stop extends React.Component<Props> {\n  static propTypes = propTypes;\n\n  static defaultProps = {\n    stopColor: '#000',\n    stopOpacity: 1,\n  };\n\n  render() {\n    const { children, ...rest } = this.props;\n    return <svg_stop {...rest}>{children}</svg_stop>;\n  }\n}\n"
  },
  {
    "path": "src/components/Svg/Svg.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { ViewPropTypes } from '../View';\nimport { StyleSheet } from '../../stylesheet';\nimport { Circle } from './Circle';\nimport { ClipPath } from './ClipPath';\nimport { Defs } from './Defs';\nimport { Ellipse } from './Ellipse';\nimport { G } from './G';\nimport { SVGImage as Image } from './Image';\nimport { Line } from './Line';\nimport { LinearGradient } from './LinearGradient';\nimport { Path } from './Path';\nimport { Pattern } from './Pattern';\nimport { Polygon } from './Polygon';\nimport { Polyline } from './Polyline';\nimport { RadialGradient } from './RadialGradient';\nimport { Rect } from './Rect';\nimport { Stop } from './Stop';\nimport { Symbol } from './Symbol';\nimport { Text } from './Text';\nimport { TextPath } from './TextPath';\nimport { TSpan } from './TSpan';\nimport { Use } from './Use';\n\nconst propTypes = {\n  ...ViewPropTypes,\n  opacity: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n  width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n  height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n  // more detail https://svgwg.org/svg2-draft/coords.html#ViewBoxAttribute\n  viewBox: PropTypes.string,\n  preserveAspectRatio: PropTypes.string,\n  xmlns: PropTypes.string,\n  'xmlns:xlink': PropTypes.string,\n};\n\nexport type Props = PropTypes.InferProps<typeof propTypes>;\n\nexport class Svg extends React.Component<Props> {\n  static displayName = 'Svg';\n\n  static propTypes = propTypes;\n\n  static defaultProps = {\n    preserveAspectRatio: 'xMidYMid meet',\n  };\n\n  static Circle = Circle;\n\n  static ClipPath = ClipPath;\n\n  static Defs = Defs;\n\n  static Ellipse = Ellipse;\n\n  static G = G;\n\n  static Image = Image;\n\n  static Line = Line;\n\n  static LinearGradient = LinearGradient;\n\n  static Path = Path;\n\n  static Pattern = Pattern;\n\n  static Polygon = Polygon;\n\n  static Polyline = Polyline;\n\n  static RadialGradient = RadialGradient;\n\n  static Rect = Rect;\n\n  static Stop = Stop;\n\n  static Symbol = Symbol;\n\n  static Text = Text;\n\n  static TextPath = TextPath;\n\n  static TSpan = TSpan;\n\n  static Use = Use;\n\n  render() {\n    const { children, style, ...rest } = this.props;\n\n    return (\n      <sketch_svg {...rest} style={StyleSheet.flatten(style)}>\n        {children}\n      </sketch_svg>\n    );\n  }\n}\n"
  },
  {
    "path": "src/components/Svg/Symbol.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\n\nconst propTypes = {\n  id: PropTypes.string.isRequired,\n  viewBox: PropTypes.string,\n  preserveAspectRatio: PropTypes.string,\n  children: PropTypes.node.isRequired,\n};\n\ntype Props = PropTypes.InferProps<typeof propTypes>;\n\nexport class Symbol extends React.Component<Props> {\n  static propTypes = propTypes;\n\n  render() {\n    const { children, ...rest } = this.props;\n\n    return <svg_symbol {...rest}>{children}</svg_symbol>;\n  }\n}\n"
  },
  {
    "path": "src/components/Svg/TSpan.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { textProps } from './props';\n\ntype Props = PropTypes.InferProps<typeof textProps>;\n\nexport class TSpan extends React.Component<Props> {\n  static propTypes = textProps;\n\n  static childContextTypes = {\n    isInAParentText: PropTypes.bool,\n  };\n\n  getChildContext() {\n    return {\n      isInAParentText: true,\n    };\n  }\n\n  getContextTypes() {\n    return {\n      isInAParentText: PropTypes.bool,\n    };\n  }\n\n  render() {\n    const { children, ...rest } = this.props;\n    return <svg_tspan {...rest}>{children}</svg_tspan>;\n  }\n}\n"
  },
  {
    "path": "src/components/Svg/Text.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { textProps } from './props';\n\ntype Props = PropTypes.InferProps<typeof textProps>;\n\nexport class Text extends React.Component<Props> {\n  static propTypes = textProps;\n\n  static childContextTypes = {\n    isInAParentText: PropTypes.bool,\n  };\n\n  getChildContext() {\n    return {\n      isInAParentText: true,\n    };\n  }\n\n  getContextTypes() {\n    return {\n      isInAParentText: PropTypes.bool,\n    };\n  }\n\n  render() {\n    const { children, ...rest } = this.props;\n    return <svg_text {...rest}>{children}</svg_text>;\n  }\n}\n"
  },
  {
    "path": "src/components/Svg/TextPath.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { textPathProps } from './props';\n\ntype Props = PropTypes.InferProps<typeof textPathProps>;\n\nconst idExpReg = /^#(.+)$/;\n\nexport class TextPath extends React.Component<Props> {\n  static propTypes = textPathProps;\n\n  render() {\n    if (!this.props.href || !this.props.href.match(idExpReg)) {\n      console.warn(\n        `Invalid \\`href\\` prop for \\`TextPath\\` element, expected a href like \\`\"#id\"\\`, but got: \"${this.props.href}\"`,\n      );\n    }\n\n    const { children, ...rest } = this.props;\n\n    return <svg_textPath {...rest}>{children}</svg_textPath>;\n  }\n}\n"
  },
  {
    "path": "src/components/Svg/Use.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { pathProps, numberProp } from './props';\n\nconst propTypes = {\n  href: PropTypes.string.isRequired,\n  width: numberProp, // Just for reusing `Symbol`\n  height: numberProp, //  Just for reusing `Symbol`\n  ...pathProps,\n};\n\ntype Props = PropTypes.InferProps<typeof propTypes>;\n\nconst idExpReg = /^#(.+)$/;\n\nexport class Use extends React.Component<Props> {\n  static propTypes = propTypes;\n\n  render() {\n    const { href } = this.props;\n    // match \"url(#pattern)\"\n    const matched = href.match(idExpReg);\n\n    if (!href || !matched) {\n      console.warn(\n        `Invalid \\`href\\` prop for \\`Use\\` element, expected a href like \\`\"#id\"\\`, but got: \"${href}\"`,\n      );\n    }\n    const { children, ...rest } = this.props;\n    return <svg_use {...rest}>{children}</svg_use>;\n  }\n}\n"
  },
  {
    "path": "src/components/Svg/index.tsx",
    "content": "export { Circle } from './Circle';\nexport { ClipPath } from './ClipPath';\nexport { Defs } from './Defs';\nexport { Ellipse } from './Ellipse';\nexport { G } from './G';\nexport { SVGImage as Image } from './Image';\nexport { Line } from './Line';\nexport { LinearGradient } from './LinearGradient';\nexport { Path } from './Path';\nexport { Pattern } from './Pattern';\nexport { Polygon } from './Polygon';\nexport { Polyline } from './Polyline';\nexport { RadialGradient } from './RadialGradient';\nexport { Rect } from './Rect';\nexport { Stop } from './Stop';\nexport { Symbol } from './Symbol';\nexport { Text } from './Text';\nexport { TextPath } from './TextPath';\nexport { TSpan } from './TSpan';\nexport { Use } from './Use';\nexport { Svg as default } from './Svg';\n"
  },
  {
    "path": "src/components/Svg/props.ts",
    "content": "import * as PropTypes from 'prop-types';\n\nconst numberProp = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);\nconst numberArrayProp = PropTypes.oneOfType([PropTypes.arrayOf(numberProp), numberProp]);\n\nconst fillProps = {\n  fill: PropTypes.string,\n  fillOpacity: numberProp,\n  fillRule: PropTypes.oneOf(['evenodd', 'nonzero']),\n};\n\nconst clipProps = {\n  clipRule: PropTypes.oneOf(['evenodd', 'nonzero']),\n  clipPath: PropTypes.string,\n};\n\nconst definationProps = {\n  name: PropTypes.string,\n};\n\nconst strokeProps = {\n  stroke: PropTypes.string,\n  strokeWidth: numberProp,\n  strokeOpacity: numberProp,\n  strokeDasharray: numberArrayProp,\n  strokeDashoffset: numberProp,\n  strokeLinecap: PropTypes.oneOf(['butt', 'square', 'round']),\n  strokeLinejoin: PropTypes.oneOf(['miter', 'bevel', 'round']),\n  strokeAlignment: PropTypes.oneOf(['center', 'inner', 'outer']),\n  strokeMiterlimit: numberProp,\n};\n\nconst transformProps = {\n  scale: numberProp,\n  scaleX: numberProp,\n  scaleY: numberProp,\n  rotate: numberProp,\n  rotation: numberProp,\n  translate: numberProp,\n  translateX: numberProp,\n  translateY: numberProp,\n  x: numberProp,\n  y: numberProp,\n  origin: numberProp,\n  originX: numberProp,\n  originY: numberProp,\n  skew: numberProp,\n  skewX: numberProp,\n  skewY: numberProp,\n  transform: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),\n};\n\nconst pathProps = {\n  ...fillProps,\n  ...strokeProps,\n  ...clipProps,\n  ...transformProps,\n  ...definationProps,\n};\n\n// normal | italic | oblique | inherit\n// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/font-style\nconst fontStyle = PropTypes.oneOf(['normal', 'italic', 'oblique']);\n\n// normal | small-caps | inherit\n// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/font-variant\nconst fontVariant = PropTypes.oneOf(['normal', 'small-caps']);\n\n// normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900\n// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/font-weight\nconst fontWeight = PropTypes.oneOf([\n  'normal',\n  'bold',\n  'bolder',\n  'lighter',\n  '100',\n  '200',\n  '300',\n  '400',\n  '500',\n  '600',\n  '700',\n  '800',\n  '900',\n]);\n\n// normal | wider | narrower | ultra-condensed | extra-condensed |\n// condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded | inherit\n// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/font-stretch\nconst fontStretch = PropTypes.oneOf([\n  'normal',\n  'wider',\n  'narrower',\n  'ultra-condensed',\n  'extra-condensed',\n  'condensed',\n  'semi-condensed',\n  'semi-expanded',\n  'expanded',\n  'extra-expanded',\n  'ultra-expanded',\n]);\n\n// <absolute-size> | <relative-size> | <length> | <percentage> | inherit\n// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/font-size\nconst fontSize = numberProp;\n\n// [[<family-name> | <generic-family>],]* [<family-name> | <generic-family>] | inherit\n// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/font-family\nconst fontFamily = PropTypes.string;\n\n/*\n    font syntax [ [ <'font-style'> || <font-variant-css21> ||\n    <'font-weight'> || <'font-stretch'> ]? <'font-size'> [ / <'line-height'> ]? <'font-family'> ] |\n    caption | icon | menu | message-box | small-caption | status-bar\n    where <font-variant-css21> = [ normal | small-caps ]\n\n    Shorthand property for setting ‘font-style’, ‘font-variant’,\n    ‘font-weight’, ‘font-size’, ‘line-height’ and ‘font-family’.\n\n    The ‘line-height’ property has no effect on text layout in SVG.\n\n    Note: for the purposes of processing the ‘font’ property in SVG,\n    'line-height' is assumed to be equal the value for property ‘font-size’\n\n    https://www.w3.org/TR/SVG11/text.html#FontProperty\n    https://developer.mozilla.org/en-US/docs/Web/CSS/font\n    https://drafts.csswg.org/css-fonts-3/#font-prop\n    https://www.w3.org/TR/CSS2/fonts.html#font-shorthand\n    https://www.w3.org/TR/CSS1/#font\n*/\nconst font = PropTypes.object;\n\n// start | middle | end | inherit\n// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-anchor\nconst textAnchor = PropTypes.oneOf(['start', 'middle', 'end']);\n\n// none | underline | overline | line-through | blink | inherit\n// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-decoration\nconst textDecoration = PropTypes.oneOf(['none', 'underline', 'overline', 'line-through', 'blink']);\n\n// normal | <length> | inherit\n// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/letter-spacing\nconst letterSpacing = numberProp;\n\n// normal | <length> | inherit\n// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/word-spacing\nconst wordSpacing = numberProp;\n\n// auto | <length> | inherit\n// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/kerning\nconst kerning = numberProp;\n\n/*\nName: font-variant-ligatures\nValue: normal | none | [ <common-lig-values> || <discretionary-lig-values> ||\n  <historical-lig-values> || <contextual-alt-values> ]\n    Initial: normal\n    Applies to: all elements\n    Inherited: yes\n    Percentages: N/A\n    Media: visual\n    Computed value: as specified\n    Animatable: no\n\n  Ligatures and contextual forms are ways of combining glyphs to produce more harmonized forms.\n\n  <common-lig-values>        = [ common-ligatures | no-common-ligatures ]\n  <discretionary-lig-values> = [ discretionary-ligatures | no-discretionary-ligatures ]\n  <historical-lig-values>    = [ historical-ligatures | no-historical-ligatures ]\n  <contextual-alt-values>    = [ contextual | no-contextual ]\n\n  https://developer.mozilla.org/en/docs/Web/CSS/font-variant-ligatures\n  https://www.w3.org/TR/css-fonts-3/#font-variant-ligatures-prop\n*/\nconst fontVariantLigatures = PropTypes.oneOf(['normal', 'none']);\n\nconst fontProps = {\n  fontStyle,\n  fontVariant,\n  fontWeight,\n  fontStretch,\n  fontSize,\n  fontFamily,\n  textAnchor,\n  textDecoration,\n  letterSpacing,\n  wordSpacing,\n  kerning,\n  fontVariantLigatures,\n  font,\n};\n\n/*\n  Name Value Initial value Animatable\n  lengthAdjust spacing | spacingAndGlyphs spacing yes\n  https://svgwg.org/svg2-draft/text.html#TextElementLengthAdjustAttribute\n  https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/lengthAdjust\n */\nconst lengthAdjust = PropTypes.oneOf(['spacing', 'spacingAndGlyphs']);\n\n/*\n  Name Value Initial value Animatable\n  textLength <length> | <percentage> | <number> See below yes\n  https://svgwg.org/svg2-draft/text.html#TextElementTextLengthAttribute\n  https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/textLength\n*/\nconst textLength = numberProp;\n\n/*\n  2.2. Transverse Box Alignment: the vertical-align property\n\n  Name: vertical-align\n  Value: <‘baseline-shift’> || <‘alignment-baseline’>\n  Initial: baseline\n  Applies to: inline-level boxes\n  Inherited: no\n  Percentages: N/A\n  Media: visual\n  Computed value: as specified\n  Canonical order: per grammar\n  Animation type: discrete\n  This shorthand property specifies how an inline-level box is aligned within the line.\n  Values are the same as for its longhand properties, see below.\n\n  Authors should use this property (vertical-align) instead of its longhands.\n\n  https://www.w3.org/TR/css-inline-3/#transverse-alignment\n  https://drafts.csswg.org/css-inline/#propdef-vertical-align\n */\nconst verticalAlign = numberProp;\n\n/*\n  Name: alignment-baseline\n\n  1.1 Value: auto | baseline | before-edge | text-before-edge | middle | central |\n  after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | inherit\n  2.0 Value: baseline | text-bottom | alphabetic | ideographic | middle | central |\n  mathematical | text-top | bottom | center | top\n  Initial: baseline\n  Applies to: inline-level boxes, flex items, grid items, table cells\n  Inherited: no\n  Percentages: N/A\n  Media: visual\n  Computed value: as specified\n  Canonical order: per grammar\n  Animation type: discrete\n  https://drafts.csswg.org/css-inline/#propdef-alignment-baseline\n  https://www.w3.org/TR/SVG11/text.html#AlignmentBaselineProperty\n  https://svgwg.org/svg2-draft/text.html#AlignmentBaselineProperty\n  https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/alignment-baseline\n*/\nconst alignmentBaseline = PropTypes.oneOf([\n  'baseline',\n  'text-bottom',\n  'alphabetic',\n  'ideographic',\n  'middle',\n  'central',\n  'mathematical',\n  'text-top',\n  'bottom',\n  'center',\n  'top',\n  'text-before-edge',\n  'text-after-edge',\n  'before-edge',\n  'after-edge',\n  'hanging',\n]);\n\n/*\n  2.2.2. Alignment Shift: baseline-shift longhand\n\n  Name: baseline-shift\n  Value: <length> | <percentage> | sub | super\n  Initial: 0\n  Applies to: inline-level boxes\n  Inherited: no\n  Percentages: refer to the used value of line-height\n  Media: visual\n  Computed value: absolute length, percentage, or keyword specified\n  Animation type: discrete\n\n  This property specifies by how much the box is shifted up from its alignment point.\n  It does not apply when alignment-baseline is top or bottom.\n\n  https://www.w3.org/TR/css-inline-3/#propdef-baseline-shift\n*/\nconst baselineShift = PropTypes.oneOfType([\n  PropTypes.oneOf(['sub', 'super', 'baseline']),\n  PropTypes.arrayOf(numberProp),\n  numberProp,\n]);\n\n/*\n  6.12. Low-level font feature settings control: the font-feature-settings property\n\n  Name: font-feature-settings\n  Value: normal | <feature-tag-value> #\n  Initial: normal\n  Applies to: all elements\n  Inherited: yes\n  Percentages: N/A\n  Media: visual\n  Computed value: as specified\n  Animatable: no\n\n    This property provides low-level control over OpenType font features.\n\n    It is intended as a way of providing access to font features\n    that are not widely used but are needed for a particular use case.\n\n    Authors should generally use ‘font-variant’ and its related subproperties\n    whenever possible and only use this property for special cases where its use\n    is the only way of accessing a particular infrequently used font feature.\n\n    enable small caps and use second swash alternate\n    font-feature-settings: \"smcp\", \"swsh\" 2;\n    A value of ‘normal’ means that no change in glyph selection or positioning\n    occurs due to this property.\n\n    Feature tag values have the following syntax:\n\n    <feature-tag-value> = <string> [ <integer> | on | off ]?\n    The <string> is a case-sensitive OpenType feature tag. As specified in the\n    OpenType specification, feature tags contain four ASCII characters.\n\n    Tag strings longer or shorter than four characters,\n    or containing characters outside the U+20–7E codepoint range are invalid.\n\n    Feature tags need only match a feature tag defined in the font,\n    so they are not limited to explicitly registered OpenType features.\n\n    Fonts defining custom feature tags should follow the tag name rules\n    defined in the OpenType specification [OPENTYPE-FEATURES].\n\n    Feature tags not present in the font are ignored;\n    a user agent must not attempt to synthesize fallback behavior based on these feature tags.\n\n    The one exception is that user agents may synthetically support the kern feature with fonts\n    that contain kerning data in the form of a ‘kern’ table but lack kern feature\n    support in the ‘GPOS’ table.\n\n    In general, authors should use the ‘font-kerning’ property to explicitly\n    enable or disable kerning\n    since this property always affects fonts with either type of kerning data.\n\n    If present, a value indicates an index used for glyph selection.\n\n    An <integer> value must be 0 or greater.\n\n    A value of 0 indicates that the feature is disabled.\n\n    For boolean features, a value of 1 enables the feature.\n\n    For non-boolean features, a value of 1 or greater enables the\n    feature and indicates the feature selection index.\n\n    A value of ‘on’ is synonymous with 1 and ‘off’ is synonymous with 0.\n\n    If the value is omitted, a value of 1 is assumed.\n\n    font-feature-settings: \"dlig\" 1;       /* dlig=1 enable discretionary ligatures * /\n    font-feature-settings: \"smcp\" on;      /* smcp=1 enable small caps * /\n    font-feature-settings: 'c2sc';         /* c2sc=1 enable caps to small caps * /\n    font-feature-settings: \"liga\" off;     /* liga=0 no common ligatures * /\n    font-feature-settings: \"tnum\", 'hist'; /* tnum=1, hist=1 enable tabular numbers\n                                              and historical forms * /\n    font-feature-settings: \"tnum\" \"hist\";  /* invalid, need a comma-delimited list * /\n    font-feature-settings: \"silly\" off;    /* invalid, tag too long * /\n    font-feature-settings: \"PKRN\";         /* PKRN=1 enable custom feature * /\n    font-feature-settings: dlig;           /* invalid, tag must be a string * /\n\n    When values greater than the range supported by the font are specified,\n    the behavior is explicitly undefined.\n\n    For boolean features, in general these will enable the feature.\n\n    For non-boolean features, out of range values will in general be equivalent to a 0 value.\n\n    However, in both cases the exact behavior will depend upon the way the font is designed\n    (specifically, which type of lookup is used to define the feature).\n\n    Although specifically defined for OpenType feature tags,\n    feature tags for other modern font formats that support font features\n    may be added in the future.\n\n    Where possible, features defined for other font formats\n    should attempt to follow the pattern of registered OpenType tags.\n\n    The Japanese text below will be rendered with half-width kana characters:\n\n    body { font-feature-settings: \"hwid\"; /* Half-width OpenType feature * / }\n\n    <p>毎日カレー食べてるのに、飽きない</p>\n\n    https://drafts.csswg.org/css-fonts-3/#propdef-font-feature-settings\n    https://developer.mozilla.org/en/docs/Web/CSS/font-feature-settings\n*/\nconst fontFeatureSettings = PropTypes.string;\n\nconst textSpecificProps = {\n  ...pathProps,\n  ...fontProps,\n  alignmentBaseline,\n  baselineShift,\n  verticalAlign,\n  lengthAdjust,\n  textLength,\n  fontData: PropTypes.object,\n  fontFeatureSettings,\n};\n\n// https://svgwg.org/svg2-draft/text.html#TSpanAttributes\nconst textProps = {\n  ...textSpecificProps,\n  dx: numberArrayProp,\n  dy: numberArrayProp,\n};\n\n/*\n  Name\n  side\n  Value\n  left | right\n  initial value\n  left\n  Animatable\n  yes\n  https://svgwg.org/svg2-draft/text.html#TextPathElementSideAttribute\n*/\nconst side = PropTypes.oneOf(['left', 'right']);\n\n/*\n  Name\n  startOffset\n  Value\n  <length> | <percentage> | <number>\n  initial value\n  0\n  Animatable\n  yes\n  https://svgwg.org/svg2-draft/text.html#TextPathElementStartOffsetAttribute\n  https://developer.mozilla.org/en/docs/Web/SVG/Element/textPath\n */\nconst startOffset = numberProp;\n\n/*\n  Name\n  method\n  Value\n  align | stretch\n  initial value\n  align\n  Animatable\n  yes\n  https://svgwg.org/svg2-draft/text.html#TextPathElementMethodAttribute\n  https://developer.mozilla.org/en/docs/Web/SVG/Element/textPath\n */\nconst method = PropTypes.oneOf(['align', 'stretch']);\n\n/*\n  Name\n  spacing\n  Value\n  auto | exact\n  initial value\n  exact\n  Animatable\n  yes\n  https://svgwg.org/svg2-draft/text.html#TextPathElementSpacingAttribute\n  https://developer.mozilla.org/en/docs/Web/SVG/Element/textPath\n */\nconst spacing = PropTypes.oneOf(['auto', 'exact']);\n\n/*\n  Name\n  mid-line\n  Value\n  sharp | smooth\n  initial value\n  smooth\n  Animatable\n  yes\n */\nconst midLine = PropTypes.oneOf(['sharp', 'smooth']);\n\n// https://svgwg.org/svg2-draft/text.html#TextPathAttributes\n// https://developer.mozilla.org/en/docs/Web/SVG/Element/textPath\nconst textPathProps = {\n  ...textSpecificProps,\n  href: PropTypes.string.isRequired,\n  startOffset,\n  method,\n  spacing,\n  side,\n  midLine,\n};\n\nexport {\n  numberProp,\n  fillProps,\n  strokeProps,\n  fontProps,\n  textProps,\n  textPathProps,\n  clipProps,\n  pathProps,\n};\n"
  },
  {
    "path": "src/components/Text.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { or } from 'airbnb-prop-types';\nimport { StyleSheet } from '../stylesheet';\nimport { TextStylePropTypes } from './TextStylePropTypes';\nimport { ViewPropTypes } from './View';\n\nexport const TextPropTypes = {\n  ...ViewPropTypes,\n  style: or([PropTypes.shape(TextStylePropTypes), PropTypes.number]),\n};\n\nexport type Props = PropTypes.InferProps<typeof TextPropTypes>;\n\n/**\n * @example\n * <Text name='Foo' style={style}>\n *   Hello World!\n * </Text>\n */\nexport class Text extends React.Component<Props> {\n  static propTypes = TextPropTypes;\n\n  render() {\n    return (\n      <sketch_text\n        name={this.props.name}\n        style={StyleSheet.flatten(this.props.style)}\n        resizingConstraint={this.props.resizingConstraint}\n      >\n        {this.props.children}\n      </sketch_text>\n    );\n  }\n}\n"
  },
  {
    "path": "src/components/TextStylePropTypes.ts",
    "content": "import * as PropTypes from 'prop-types';\nimport { ViewStylePropTypes, Color } from './ViewStylePropTypes';\n\nexport const TextStylePropTypes = {\n  ...ViewStylePropTypes,\n  fontFamily: PropTypes.string,\n  fontSize: PropTypes.number,\n  fontStyle: PropTypes.oneOf<'normal' | 'italic'>(['normal', 'italic']),\n  fontWeight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n  textDecoration: PropTypes.oneOf<'none' | 'underline' | 'double' | 'line-through'>([\n    'none',\n    'underline',\n    'double',\n    'line-through',\n  ]),\n  textShadowOpacity: PropTypes.number,\n  textShadowSpread: PropTypes.number,\n  textShadowOffset: PropTypes.shape({ width: PropTypes.number, height: PropTypes.number }),\n  textShadowRadius: PropTypes.number,\n  textShadowColor: Color,\n  textTransform: PropTypes.oneOf<'uppercase' | 'lowercase'>(['uppercase', 'lowercase']),\n  letterSpacing: PropTypes.number,\n  lineHeight: PropTypes.number,\n  textAlign: PropTypes.oneOf<'auto' | 'left' | 'right' | 'center' | 'justify'>([\n    'auto',\n    'left',\n    'right',\n    'center',\n    'justify',\n  ]),\n  paragraphSpacing: PropTypes.number,\n  writingDirection: PropTypes.oneOf<'auto' | 'ltr' | 'rtl'>(['auto', 'ltr', 'rtl']),\n};\n"
  },
  {
    "path": "src/components/View.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { or } from 'airbnb-prop-types';\nimport { StyleSheet } from '../stylesheet';\nimport { ViewStylePropTypes } from './ViewStylePropTypes';\nimport { ResizingConstraintPropTypes } from './ResizingConstraintPropTypes';\nimport { ShadowsPropTypes } from './ShadowsPropTypes';\n\nexport const ViewPropTypes = {\n  // TODO(lmr): do some nice warning stuff like RN does\n  style: or([PropTypes.shape(ViewStylePropTypes), PropTypes.number]),\n  name: PropTypes.string,\n  resizingConstraint: PropTypes.shape({\n    ...ResizingConstraintPropTypes,\n  }),\n  shadows: PropTypes.arrayOf(\n    PropTypes.shape({\n      ...ShadowsPropTypes,\n    }),\n  ),\n  flow: PropTypes.shape({\n    targetId: PropTypes.string,\n    target: PropTypes.string,\n    animationType: PropTypes.string,\n  }),\n  children: PropTypes.node,\n};\n\nexport type Props = PropTypes.InferProps<typeof ViewPropTypes>;\n\nexport class View extends React.Component<Props> {\n  static propTypes = ViewPropTypes;\n\n  static defaultProps = {\n    name: 'View',\n  };\n\n  render() {\n    return (\n      <sketch_view\n        name={this.props.name}\n        style={StyleSheet.flatten(this.props.style)}\n        resizingConstraint={this.props.resizingConstraint}\n        shadows={this.props.shadows}\n        flow={this.props.flow}\n      >\n        {this.props.children}\n      </sketch_view>\n    );\n  }\n}\n"
  },
  {
    "path": "src/components/ViewStylePropTypes.ts",
    "content": "import * as PropTypes from 'prop-types';\n\nexport const BorderStyle = PropTypes.oneOf<'solid' | 'dotted' | 'dashed'>([\n  'solid',\n  'dotted',\n  'dashed',\n]);\nexport const Color = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);\nexport const Overflow = PropTypes.oneOf<'visible' | 'hidden' | 'scroll'>([\n  'visible',\n  'hidden',\n  'scroll',\n]);\n\nexport const ViewStylePropTypes = {\n  display: PropTypes.oneOf(['flex', 'none']),\n  color: Color,\n  shadowColor: Color,\n  shadowInner: PropTypes.bool,\n  shadowSpread: PropTypes.number,\n  shadowOffset: PropTypes.shape({\n    width: PropTypes.number,\n    height: PropTypes.number,\n  }),\n  shadowOpacity: PropTypes.number,\n  shadowRadius: PropTypes.number,\n  width: PropTypes.number,\n  height: PropTypes.number,\n  top: PropTypes.number,\n  left: PropTypes.number,\n  right: PropTypes.number,\n  bottom: PropTypes.number,\n  minWidth: PropTypes.number,\n  maxWidth: PropTypes.number,\n  minHeight: PropTypes.number,\n  maxHeight: PropTypes.number,\n  margin: PropTypes.number,\n  marginVertical: PropTypes.number,\n  marginHorizontal: PropTypes.number,\n  marginTop: PropTypes.number,\n  marginBottom: PropTypes.number,\n  marginLeft: PropTypes.number,\n  marginRight: PropTypes.number,\n  padding: PropTypes.number,\n  paddingVertical: PropTypes.number,\n  paddingHorizontal: PropTypes.number,\n  paddingTop: PropTypes.number,\n  paddingBottom: PropTypes.number,\n  paddingLeft: PropTypes.number,\n  paddingRight: PropTypes.number,\n  position: PropTypes.oneOf<'absolute' | 'relative'>(['absolute', 'relative']),\n  flexDirection: PropTypes.oneOf<'row' | 'row-reverse' | 'column' | 'column-reverse'>([\n    'row',\n    'row-reverse',\n    'column',\n    'column-reverse',\n  ]),\n  flexWrap: PropTypes.oneOf<'wrap' | 'nowrap' | 'wrap-reverse'>(['wrap', 'nowrap', 'wrap-reverse']),\n  justifyContent: PropTypes.oneOf<\n    'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around'\n  >(['flex-start', 'flex-end', 'center', 'space-between', 'space-around']),\n  alignContent: PropTypes.oneOf<\n    | 'flex-start'\n    | 'flex-end'\n    | 'center'\n    | 'space-between'\n    | 'space-around'\n    | 'stretch'\n    | 'baseline'\n    | 'auto'\n  >([\n    'flex-start',\n    'flex-end',\n    'center',\n    'space-between',\n    'space-around',\n    'stretch',\n    'baseline',\n    'auto',\n  ]),\n  alignItems: PropTypes.oneOf<'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline'>([\n    'flex-start',\n    'flex-end',\n    'center',\n    'stretch',\n    'baseline',\n  ]),\n  alignSelf: PropTypes.oneOf<\n    'auto' | 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline'\n  >(['auto', 'flex-start', 'flex-end', 'center', 'stretch', 'baseline']),\n  overflow: Overflow,\n  overflowX: Overflow,\n  overflowY: Overflow,\n  flex: PropTypes.number,\n  flexGrow: PropTypes.number,\n  flexShrink: PropTypes.number,\n  flexBasis: PropTypes.number,\n  aspectRatio: PropTypes.number,\n  zIndex: PropTypes.number,\n  backfaceVisibility: PropTypes.oneOf<'visible' | 'hidden'>(['visible', 'hidden']),\n  backgroundColor: Color,\n  borderColor: Color,\n  borderTopColor: Color,\n  borderRightColor: Color,\n  borderBottomColor: Color,\n  borderLeftColor: Color,\n  borderRadius: PropTypes.number,\n  borderTopLeftRadius: PropTypes.number,\n  borderTopRightRadius: PropTypes.number,\n  borderBottomLeftRadius: PropTypes.number,\n  borderBottomRightRadius: PropTypes.number,\n  borderStyle: BorderStyle,\n  borderTopStyle: BorderStyle,\n  borderRightStyle: BorderStyle,\n  borderBottomStyle: BorderStyle,\n  borderLeftStyle: BorderStyle,\n  borderWidth: PropTypes.number,\n  borderTopWidth: PropTypes.number,\n  borderRightWidth: PropTypes.number,\n  borderBottomWidth: PropTypes.number,\n  borderLeftWidth: PropTypes.number,\n  opacity: PropTypes.number,\n  transform: PropTypes.string,\n  transformOrigin: PropTypes.string,\n};\n"
  },
  {
    "path": "src/components/index.ts",
    "content": "export { Document } from './Document';\nexport { Page } from './Page';\nexport { Artboard } from './Artboard';\nexport { Image } from './Image';\nexport { RedBox } from './RedBox';\nexport { View } from './View';\nexport { Text } from './Text';\nimport Svg from './Svg';\nexport { Svg };\n"
  },
  {
    "path": "src/context.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\n\nimport { Style } from './stylesheet/types';\n\nconst initialArtboardState = {\n  width: 0,\n  height: 0,\n  scale: 1,\n  fontScale: 1,\n};\n\nexport const ArtboardContext = React.createContext({\n  state: initialArtboardState,\n});\n\nexport const useWindowDimensions = () => {\n  const { state } = React.useContext(ArtboardContext);\n  const { width, height, scale, fontScale } = state || {};\n\n  return { width, height, scale, fontScale };\n};\n\nconst ArtboardPropTypes = {\n  viewport: PropTypes.shape({\n    width: PropTypes.number,\n    height: PropTypes.number,\n    name: PropTypes.string,\n    scale: PropTypes.number,\n    fontScale: PropTypes.number,\n  }),\n  children: PropTypes.node,\n};\n\ntype ArtboardProps = PropTypes.InferProps<typeof ArtboardPropTypes> & {\n  children: any;\n  style?: Style;\n};\n\nexport const ArtboardProvider = ({ children, viewport, style }: ArtboardProps) => {\n  if (!viewport) {\n    return children;\n  }\n\n  const { state: oState } = React.useContext(ArtboardContext);\n\n  const state = {\n    ...oState,\n    width: viewport.width || (style || {}).width || oState.width,\n    height: viewport.height || (style || {}).height || oState.height,\n    scale: viewport.scale || oState.scale,\n    fontScale: viewport.fontScale || oState.scale,\n  };\n\n  return <ArtboardContext.Provider value={{ state }}>{children}</ArtboardContext.Provider>;\n};\n"
  },
  {
    "path": "src/entrypoint.sketch.ts",
    "content": "import { render as _render } from './render';\nimport { renderToJSON as _renderToJSON } from './renderToJSON';\nimport { makeSymbol as _makeSymbol, SymbolMasterProps } from './symbol';\nimport {\n  SketchLayer,\n  WrappedSketchLayer,\n  SketchDocumentData,\n  WrappedSketchDocument,\n  SketchDocument,\n  PlatformBridge,\n} from './types';\nimport { TextStyles as _TextStyles } from './sharedStyles/TextStyles';\nimport SketchBridge from './platformBridges/sketch';\n\nexport function render(\n  element: React.ReactElement,\n  container?: SketchLayer | WrappedSketchLayer,\n  platformBridge: PlatformBridge = SketchBridge,\n) {\n  return _render(platformBridge)(element, container);\n}\n\nexport function renderToJSON(\n  element: React.ReactElement,\n  platformBridge: PlatformBridge = SketchBridge,\n) {\n  return _renderToJSON(platformBridge)(element);\n}\n\nexport function makeSymbol(\n  Component: React.ComponentType<any>,\n  symbolProps: string | SymbolMasterProps,\n  document: SketchDocumentData | SketchDocument | WrappedSketchDocument | undefined,\n  bridge: PlatformBridge = SketchBridge,\n) {\n  return _makeSymbol(bridge)(Component, symbolProps, document);\n}\n\nexport const TextStyles = _TextStyles(() => SketchBridge);\n"
  },
  {
    "path": "src/entrypoint.ts",
    "content": "import { render as _render } from './render';\nimport { renderToJSON as _renderToJSON } from './renderToJSON';\nimport { makeSymbol as _makeSymbol, SymbolMasterProps } from './symbol';\n\nimport {\n  SketchLayer,\n  WrappedSketchLayer,\n  SketchDocumentData,\n  WrappedSketchDocument,\n  SketchDocument,\n  PlatformBridge,\n} from './types';\n\nimport { TextStyles as _TextStyles } from './sharedStyles/TextStyles';\n\nfunction getDefaultPlatformBridge() {\n  return require('./platformBridges/macos').default;\n}\n\nexport function render(\n  element: React.ReactElement,\n  container?: SketchLayer | WrappedSketchLayer,\n  platformBridge: PlatformBridge = getDefaultPlatformBridge(),\n) {\n  return _render(platformBridge)(element, container);\n}\n\nexport function renderToJSON(\n  element: React.ReactElement,\n  platformBridge: PlatformBridge = getDefaultPlatformBridge(),\n) {\n  return _renderToJSON(platformBridge)(element);\n}\n\nexport function makeSymbol(\n  Component: React.ComponentType<any>,\n  symbolProps: string | SymbolMasterProps,\n  document: SketchDocumentData | SketchDocument | WrappedSketchDocument | undefined,\n  bridge: PlatformBridge = getDefaultPlatformBridge(),\n) {\n  return _makeSymbol(bridge)(Component, symbolProps, document);\n}\n\nexport const TextStyles = _TextStyles(() => getDefaultPlatformBridge());\n"
  },
  {
    "path": "src/flexToSketchJSON.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport * as renderers from './renderers';\nimport { SketchRenderer } from './renderers/SketchRenderer';\nimport { TreeNode, PlatformBridge } from './types';\n\nfunction missingRendererError(type: string, annotations?: string) {\n  return new Error(\n    `Could not find renderer for type '${type}'.${annotations ? `\\n${annotations}` : ''}`,\n  );\n}\n\nexport const flexToSketchJSON = (bridge: PlatformBridge) => (\n  node: TreeNode | string,\n):\n  | FileFormat.SymbolMaster\n  | FileFormat.Artboard\n  | FileFormat.Group\n  | FileFormat.ShapeGroup\n  | FileFormat.SymbolInstance => {\n  if (typeof node === 'string') {\n    throw missingRendererError('string');\n  }\n  const { type, children } = node;\n\n  // Give some insight as to why there might be issues\n  // specific to Page and Document components or SVG components\n  if (type === 'sketch_document') {\n    throw missingRendererError(\n      type,\n      'Be sure to only have <Page> components as children of <Document>.',\n    );\n  }\n\n  // @ts-ignore\n  const Renderer: typeof SketchRenderer | null = renderers[type];\n\n  if (Renderer == null) {\n    if (type.indexOf('svg') === 0) {\n      // the svg renderer should stop the walk down the tree so it shouldn't happen\n      throw missingRendererError(\n        type,\n        'Be sure to always have <Svg.*> components as children of <Svg>.',\n      );\n    }\n    throw missingRendererError(type);\n  }\n\n  const renderer = new Renderer(bridge);\n  const groupLayer = renderer.renderGroupLayer(node);\n\n  if (groupLayer._class === 'symbolInstance') {\n    return groupLayer;\n  }\n\n  const backingLayers = renderer.renderBackingLayers(node);\n\n  // stopping the walk down the tree if we have an svg\n  const curriedFlexToSketchJSON = flexToSketchJSON(bridge);\n  const sublayers =\n    children && type !== 'sketch_svg'\n      ? children.map((child) => curriedFlexToSketchJSON(child))\n      : [];\n\n  // Filter out anything null, undefined\n  const layers = [...backingLayers, ...sublayers].filter((l) => l);\n\n  return { ...groupLayer, layers };\n};\n"
  },
  {
    "path": "src/index.ts",
    "content": "export { Platform } from './Platform';\nexport { StyleSheet } from './stylesheet';\nexport { getSymbolComponentByName, getSymbolMasterByName, injectSymbols } from './symbol';\nexport { useWindowDimensions } from './context';\n\nexport * from './components';\nexport * from './entrypoint';\n"
  },
  {
    "path": "src/jsonUtils/borders.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport { makeColorFromCSS, emptyGradient } from './models';\nimport { ViewStyle, LayoutInfo, BorderStyle, Color } from '../types';\nimport { same } from '../utils/same';\nimport { makeVerticalBorder, makeHorizontalBorder } from './shapeLayers';\nimport { makeBorderOptions } from './style';\n\nconst DEFAULT_BORDER_COLOR = 'transparent';\nexport const DEFAULT_BORDER_STYLE = 'solid';\n\nexport const createUniformBorder = (\n  width: number,\n  color: Color,\n  style: BorderStyle = DEFAULT_BORDER_STYLE,\n  position: FileFormat.BorderPosition = FileFormat.BorderPosition.Center,\n  lineCapStyle: FileFormat.LineCapStyle = FileFormat.LineCapStyle.Butt,\n  lineJoinStyle: FileFormat.LineJoinStyle = FileFormat.LineJoinStyle.Miter,\n): { borderOptions: FileFormat.BorderOptions; borders: FileFormat.Border[] } => {\n  const borderOptions = makeBorderOptions(style, width, lineCapStyle, lineJoinStyle);\n\n  const borders: FileFormat.Border[] = [\n    {\n      _class: 'border',\n      isEnabled: true,\n      color: makeColorFromCSS(color),\n      fillType: FileFormat.FillType.Color,\n      position,\n      thickness: width,\n      contextSettings: {\n        _class: 'graphicsContextSettings',\n        blendMode: FileFormat.BlendMode.Normal,\n        opacity: 1,\n      },\n      gradient: emptyGradient,\n    },\n  ];\n\n  return { borderOptions, borders };\n};\n\nexport const createBorders = (\n  content: FileFormat.ShapeGroup,\n  layout: LayoutInfo,\n  style?: ViewStyle,\n): FileFormat.ShapeGroup[] => {\n  if (!style) {\n    return [content];\n  }\n\n  const {\n    borderTopWidth = 0,\n    borderRightWidth = 0,\n    borderBottomWidth = 0,\n    borderLeftWidth = 0,\n\n    borderTopColor = DEFAULT_BORDER_COLOR,\n    borderRightColor = DEFAULT_BORDER_COLOR,\n    borderBottomColor = DEFAULT_BORDER_COLOR,\n    borderLeftColor = DEFAULT_BORDER_COLOR,\n\n    borderTopStyle = DEFAULT_BORDER_STYLE,\n    borderRightStyle = DEFAULT_BORDER_STYLE,\n    borderBottomStyle = DEFAULT_BORDER_STYLE,\n    borderLeftStyle = DEFAULT_BORDER_STYLE,\n  } = style;\n\n  if (\n    same(borderTopWidth, borderRightWidth, borderBottomWidth, borderLeftWidth) &&\n    same(borderTopColor, borderRightColor, borderBottomColor, borderLeftColor) &&\n    same(borderTopStyle, borderRightStyle, borderBottomStyle, borderLeftStyle)\n  ) {\n    // all sides have same border width\n    // in this case, we can do everything with just a single shape.\n    if (borderTopStyle !== undefined && borderTopWidth !== null) {\n      const borderOptions = makeBorderOptions(borderTopStyle, borderTopWidth);\n      if (borderOptions && content.style) {\n        content.style.borderOptions = borderOptions;\n      }\n    }\n\n    if (borderTopWidth && borderTopWidth > 0 && content.style) {\n      content.style.borders = createUniformBorder(\n        borderTopWidth,\n        borderTopColor,\n        'solid',\n        FileFormat.BorderPosition.Outside,\n      ).borders;\n      const backingLayer = content.layers ? content.layers[0] : undefined;\n      if (backingLayer) {\n        backingLayer.frame.x += borderTopWidth;\n        backingLayer.frame.y += borderTopWidth;\n        backingLayer.frame.width -= borderTopWidth * 2;\n        backingLayer.frame.height -= borderTopWidth * 2;\n      }\n    }\n\n    return [content];\n  }\n\n  content.hasClippingMask = true;\n\n  const layers = [content];\n\n  if (borderTopWidth && borderTopWidth > 0) {\n    const topBorder = makeHorizontalBorder(0, 0, layout.width, borderTopWidth, borderTopColor);\n    topBorder.name = 'Border (top)';\n\n    const borderOptions = makeBorderOptions(borderTopStyle, borderTopWidth);\n    if (borderOptions && topBorder.style) {\n      topBorder.style.borderOptions = borderOptions;\n    }\n\n    layers.push(topBorder);\n  }\n\n  if (borderRightWidth && borderRightWidth > 0) {\n    const rightBorder = makeVerticalBorder(\n      layout.width - borderRightWidth,\n      0,\n      layout.height,\n      borderRightWidth,\n      borderRightColor,\n    );\n    rightBorder.name = 'Border (right)';\n\n    const borderOptions = makeBorderOptions(borderRightStyle, borderRightWidth);\n    if (borderOptions && rightBorder.style) {\n      rightBorder.style.borderOptions = borderOptions;\n    }\n\n    layers.push(rightBorder);\n  }\n\n  if (borderBottomWidth && borderBottomWidth > 0) {\n    const bottomBorder = makeHorizontalBorder(\n      0,\n      layout.height - borderBottomWidth,\n      layout.width,\n      borderBottomWidth,\n      borderBottomColor,\n    );\n    bottomBorder.name = 'Border (bottom)';\n\n    const borderOptions = makeBorderOptions(borderBottomStyle, borderBottomWidth);\n    if (borderOptions && bottomBorder.style) {\n      bottomBorder.style.borderOptions = borderOptions;\n    }\n\n    layers.push(bottomBorder);\n  }\n\n  if (borderLeftWidth && borderLeftWidth > 0) {\n    const leftBorder = makeVerticalBorder(0, 0, layout.height, borderLeftWidth, borderLeftColor);\n    leftBorder.name = 'Border (left)';\n\n    const borderOptions = makeBorderOptions(borderLeftStyle, borderLeftWidth);\n    if (borderOptions && leftBorder.style) {\n      leftBorder.style.borderOptions = borderOptions;\n    }\n\n    layers.push(leftBorder);\n  }\n\n  return layers;\n};\n"
  },
  {
    "path": "src/jsonUtils/computeTextTree.ts",
    "content": "import { ReactTestRendererNode } from 'react-test-renderer';\nimport { TextNode } from '../types';\nimport { Context } from '../utils/Context';\nimport { VALID_TEXT_CHILDREN_TYPES } from '../utils/constants';\n\nconst walkTextTree = (textTree: ReactTestRendererNode, context: Context, textNodes: TextNode[]) => {\n  if (typeof textTree !== 'string' && !VALID_TEXT_CHILDREN_TYPES.includes(textTree.type)) {\n    throw new Error(`\"${textTree.type}\" is not a valid child for Text components`);\n  }\n\n  if (typeof textTree === 'string') {\n    textNodes.push({\n      textStyles: context.getInheritedStyles(),\n      content: textTree,\n    });\n    return;\n  }\n\n  if (textTree.children) {\n    if (textTree.props && textTree.props.style) {\n      context.addInheritableStyles(textTree.props.style);\n    }\n    for (let index = 0; index < textTree.children.length; index += 1) {\n      const textComponent = textTree.children[index];\n      walkTextTree(textComponent, context.forChildren(), textNodes);\n    }\n  }\n};\n\nexport const computeTextTree = (\n  node: ReactTestRendererNode,\n  context: Context,\n  textNodes: TextNode[] = [],\n) => {\n  if (typeof node === 'string') {\n    return [\n      {\n        textStyles: context.getInheritedStyles(),\n        content: node,\n      },\n    ];\n  }\n\n  const { children } = node;\n\n  if (children) {\n    const childContext = context.forChildren();\n    for (let index = 0; index < children.length; index += 1) {\n      const textNode = children[index];\n      if (typeof textNode === 'string') {\n        textNodes.push({\n          content: textNode,\n          textStyles: childContext.getInheritedStyles(),\n        });\n      } else if (textNode.children && textNode.children.length > 0) {\n        walkTextTree(textNode, childContext, textNodes);\n      }\n    }\n  }\n\n  return textNodes;\n};\n"
  },
  {
    "path": "src/jsonUtils/computeYogaNode.ts",
    "content": "import yoga from 'yoga-layout-prebuilt';\nimport { ReactTestRendererNode } from 'react-test-renderer';\nimport { ViewStyle, PlatformBridge } from '../types';\nimport { Context } from '../utils/Context';\nimport { createStringMeasurer } from '../utils/createStringMeasurer';\nimport { hasAnyDefined } from '../utils/hasAnyDefined';\nimport { pick } from '../utils/pick';\nimport { computeTextTree } from './computeTextTree';\nimport { INHERITABLE_FONT_STYLES } from '../utils/constants';\nimport { isDefined } from '../utils/isDefined';\nimport { getSymbolMasterById } from '../symbol';\n\n// flatten all styles (including nested) into one object\nexport const getStyles = (node: ReactTestRendererNode): ViewStyle => {\n  if (typeof node === 'string') {\n    return {};\n  }\n\n  let { style } = node.props;\n\n  if (Array.isArray(style)) {\n    const flattened = Array.prototype.concat.apply([], style);\n    const themeFlattened = Array.prototype.concat.apply([], flattened);\n    const objectsOnly = themeFlattened.filter((f) => f);\n    style = Object.assign({}, ...objectsOnly);\n  }\n\n  return style;\n};\n\nexport const computeYogaNode = (bridge: PlatformBridge) => (\n  node: ReactTestRendererNode,\n  context: Context,\n): { node: yoga.YogaNode; stop?: boolean } => {\n  const yogaNode = yoga.Node.create();\n  const hasStyle = typeof node !== 'string' && node.props && node.props.style;\n  const style: ViewStyle = hasStyle ? getStyles(node) : {};\n\n  // Setup default symbol instance dimensions\n  if (typeof node !== 'string' && node.type === 'sketch_symbolinstance') {\n    const symbolProps = node.props;\n    const symbolMaster = getSymbolMasterById(symbolProps.symbolID);\n    if (!symbolMaster) {\n      throw new Error('Cannot find Symbol Master with id ' + symbolProps.symbolID);\n    }\n    const { frame } = symbolMaster;\n    yogaNode.setWidth(frame.width);\n    yogaNode.setHeight(frame.height);\n  }\n\n  if (typeof node !== 'string' && node.type === 'sketch_svg') {\n    const svgProps = node.props;\n    // Width\n    if (isDefined(svgProps.width)) {\n      yogaNode.setWidth(svgProps.width);\n    }\n\n    // Height\n    if (isDefined(svgProps.height)) {\n      yogaNode.setHeight(svgProps.height);\n    }\n  }\n\n  if (hasStyle) {\n    // http://facebook.github.io/react-native/releases/0.48/docs/layout-props.html\n\n    // Width\n    if (isDefined(style.width)) {\n      yogaNode.setWidth(style.width);\n    }\n\n    // Height\n    if (isDefined(style.height)) {\n      yogaNode.setHeight(style.height);\n    }\n\n    // Min-Height\n    if (isDefined(style.minHeight)) {\n      yogaNode.setMinHeight(style.minHeight);\n    }\n\n    // Min-Width\n    if (isDefined(style.minWidth)) {\n      yogaNode.setMinWidth(style.minWidth);\n    }\n\n    // Max-Height\n    if (isDefined(style.maxHeight)) {\n      yogaNode.setMaxHeight(style.maxHeight);\n    }\n\n    // Min-Width\n    if (isDefined(style.maxWidth)) {\n      yogaNode.setMaxWidth(style.maxWidth);\n    }\n\n    // Margin\n    if (isDefined(style.marginTop)) {\n      yogaNode.setMargin(yoga.EDGE_TOP, style.marginTop);\n    }\n    if (isDefined(style.marginBottom)) {\n      yogaNode.setMargin(yoga.EDGE_BOTTOM, style.marginBottom);\n    }\n    if (isDefined(style.marginLeft)) {\n      yogaNode.setMargin(yoga.EDGE_LEFT, style.marginLeft);\n    }\n    if (isDefined(style.marginRight)) {\n      yogaNode.setMargin(yoga.EDGE_RIGHT, style.marginRight);\n    }\n    if (isDefined(style.marginVertical)) {\n      yogaNode.setMargin(yoga.EDGE_VERTICAL, style.marginVertical);\n    }\n    if (isDefined(style.marginHorizontal)) {\n      yogaNode.setMargin(yoga.EDGE_HORIZONTAL, style.marginHorizontal);\n    }\n    if (isDefined(style.margin)) {\n      yogaNode.setMargin(yoga.EDGE_ALL, style.margin);\n    }\n\n    // Padding\n    if (isDefined(style.paddingTop)) {\n      yogaNode.setPadding(yoga.EDGE_TOP, style.paddingTop);\n    }\n    if (isDefined(style.paddingBottom)) {\n      yogaNode.setPadding(yoga.EDGE_BOTTOM, style.paddingBottom);\n    }\n    if (isDefined(style.paddingLeft)) {\n      yogaNode.setPadding(yoga.EDGE_LEFT, style.paddingLeft);\n    }\n    if (isDefined(style.paddingRight)) {\n      yogaNode.setPadding(yoga.EDGE_RIGHT, style.paddingRight);\n    }\n    if (isDefined(style.paddingVertical)) {\n      yogaNode.setPadding(yoga.EDGE_VERTICAL, style.paddingVertical);\n    }\n    if (isDefined(style.paddingHorizontal)) {\n      yogaNode.setPadding(yoga.EDGE_HORIZONTAL, style.paddingHorizontal);\n    }\n    if (isDefined(style.padding)) {\n      yogaNode.setPadding(yoga.EDGE_ALL, style.padding);\n    }\n\n    // Border\n    if (isDefined(style.borderTopWidth)) {\n      yogaNode.setBorder(yoga.EDGE_TOP, style.borderTopWidth);\n    }\n    if (isDefined(style.borderBottomWidth)) {\n      yogaNode.setBorder(yoga.EDGE_BOTTOM, style.borderBottomWidth);\n    }\n    if (isDefined(style.borderLeftWidth)) {\n      yogaNode.setBorder(yoga.EDGE_LEFT, style.borderLeftWidth);\n    }\n    if (isDefined(style.borderRightWidth)) {\n      yogaNode.setBorder(yoga.EDGE_RIGHT, style.borderRightWidth);\n    }\n    if (isDefined(style.borderWidth)) {\n      yogaNode.setBorder(yoga.EDGE_ALL, style.borderWidth);\n    }\n\n    // Flex\n    if (isDefined(style.flex)) {\n      yogaNode.setFlex(style.flex);\n    }\n    if (isDefined(style.flexGrow)) {\n      yogaNode.setFlexGrow(style.flexGrow);\n    }\n    if (isDefined(style.flexShrink)) {\n      yogaNode.setFlexShrink(style.flexShrink);\n    }\n    if (isDefined(style.flexBasis)) {\n      yogaNode.setFlexBasis(style.flexBasis);\n    }\n\n    // Position\n    if (style.position === 'absolute') {\n      yogaNode.setPositionType(yoga.POSITION_TYPE_ABSOLUTE);\n    }\n    if (style.position === 'relative') {\n      yogaNode.setPositionType(yoga.POSITION_TYPE_RELATIVE);\n    }\n\n    if (isDefined(style.top)) {\n      yogaNode.setPosition(yoga.EDGE_TOP, style.top);\n    }\n    if (isDefined(style.left)) {\n      yogaNode.setPosition(yoga.EDGE_LEFT, style.left);\n    }\n    if (isDefined(style.right)) {\n      yogaNode.setPosition(yoga.EDGE_RIGHT, style.right);\n    }\n    if (isDefined(style.bottom)) {\n      yogaNode.setPosition(yoga.EDGE_BOTTOM, style.bottom);\n    }\n\n    // Display\n    if (style.display) {\n      if (style.display === 'flex') {\n        yogaNode.setDisplay(yoga.DISPLAY_FLEX);\n      }\n      if (style.display === 'none') {\n        yogaNode.setDisplay(yoga.DISPLAY_NONE);\n      }\n    }\n\n    // Overflow\n    if (style.overflow) {\n      if (style.overflow === 'visible') {\n        yogaNode.setOverflow(yoga.OVERFLOW_VISIBLE);\n      }\n      if (style.overflow === 'scroll') {\n        yogaNode.setOverflow(yoga.OVERFLOW_SCROLL);\n      }\n      if (style.overflow === 'hidden') {\n        yogaNode.setOverflow(yoga.OVERFLOW_HIDDEN);\n      }\n    }\n\n    // Flex direction\n    if (style.flexDirection) {\n      if (style.flexDirection === 'row') {\n        yogaNode.setFlexDirection(yoga.FLEX_DIRECTION_ROW);\n      }\n      if (style.flexDirection === 'column') {\n        yogaNode.setFlexDirection(yoga.FLEX_DIRECTION_COLUMN);\n      }\n      if (style.flexDirection === 'row-reverse') {\n        yogaNode.setFlexDirection(yoga.FLEX_DIRECTION_ROW_REVERSE);\n      }\n      if (style.flexDirection === 'column-reverse') {\n        yogaNode.setFlexDirection(yoga.FLEX_DIRECTION_COLUMN_REVERSE);\n      }\n    }\n\n    // Justify Content\n    if (style.justifyContent) {\n      if (style.justifyContent === 'flex-start') {\n        yogaNode.setJustifyContent(yoga.JUSTIFY_FLEX_START);\n      }\n      if (style.justifyContent === 'flex-end') {\n        yogaNode.setJustifyContent(yoga.JUSTIFY_FLEX_END);\n      }\n      if (style.justifyContent === 'center') {\n        yogaNode.setJustifyContent(yoga.JUSTIFY_CENTER);\n      }\n      if (style.justifyContent === 'space-between') {\n        yogaNode.setJustifyContent(yoga.JUSTIFY_SPACE_BETWEEN);\n      }\n      if (style.justifyContent === 'space-around') {\n        yogaNode.setJustifyContent(yoga.JUSTIFY_SPACE_AROUND);\n      }\n    }\n\n    // Align Content\n    if (style.alignContent) {\n      if (style.alignContent === 'flex-start') {\n        yogaNode.setAlignContent(yoga.ALIGN_FLEX_START);\n      }\n      if (style.alignContent === 'flex-end') {\n        yogaNode.setAlignContent(yoga.ALIGN_FLEX_END);\n      }\n      if (style.alignContent === 'center') {\n        yogaNode.setAlignContent(yoga.ALIGN_CENTER);\n      }\n      if (style.alignContent === 'stretch') {\n        yogaNode.setAlignContent(yoga.ALIGN_STRETCH);\n      }\n      if (style.alignContent === 'baseline') {\n        yogaNode.setAlignContent(yoga.ALIGN_BASELINE);\n      }\n      if (style.alignContent === 'space-between') {\n        yogaNode.setAlignContent(yoga.ALIGN_SPACE_BETWEEN);\n      }\n      if (style.alignContent === 'space-around') {\n        yogaNode.setAlignContent(yoga.ALIGN_SPACE_AROUND);\n      }\n      if (style.alignContent === 'auto') {\n        yogaNode.setAlignContent(yoga.ALIGN_AUTO);\n      }\n    }\n\n    // Align Items\n    if (style.alignItems) {\n      if (style.alignItems === 'flex-start') {\n        yogaNode.setAlignItems(yoga.ALIGN_FLEX_START);\n      }\n      if (style.alignItems === 'flex-end') {\n        yogaNode.setAlignItems(yoga.ALIGN_FLEX_END);\n      }\n      if (style.alignItems === 'center') {\n        yogaNode.setAlignItems(yoga.ALIGN_CENTER);\n      }\n      if (style.alignItems === 'stretch') {\n        yogaNode.setAlignItems(yoga.ALIGN_STRETCH);\n      }\n      if (style.alignItems === 'baseline') {\n        yogaNode.setAlignItems(yoga.ALIGN_BASELINE);\n      }\n    }\n\n    // Align Self\n    if (style.alignSelf) {\n      if (style.alignSelf === 'flex-start') {\n        yogaNode.setAlignSelf(yoga.ALIGN_FLEX_START);\n      }\n      if (style.alignSelf === 'flex-end') {\n        yogaNode.setAlignSelf(yoga.ALIGN_FLEX_END);\n      }\n      if (style.alignSelf === 'center') {\n        yogaNode.setAlignSelf(yoga.ALIGN_CENTER);\n      }\n      if (style.alignSelf === 'stretch') {\n        yogaNode.setAlignSelf(yoga.ALIGN_STRETCH);\n      }\n      if (style.alignSelf === 'baseline') {\n        yogaNode.setAlignSelf(yoga.ALIGN_BASELINE);\n      }\n    }\n\n    // Flex Wrap\n    if (style.flexWrap) {\n      if (style.flexWrap === 'nowrap') {\n        yogaNode.setFlexWrap(yoga.WRAP_NO_WRAP);\n      }\n      if (style.flexWrap === 'wrap') {\n        yogaNode.setFlexWrap(yoga.WRAP_WRAP);\n      }\n      if (style.flexWrap === 'wrap-reverse') {\n        yogaNode.setFlexWrap(yoga.WRAP_WRAP_REVERSE);\n      }\n    }\n  }\n\n  if (typeof node === 'string' || node.type === 'sketch_text') {\n    // If current node is a Text node, add text styles to Context to pass down to\n    // child nodes.\n    if (\n      typeof node !== 'string' &&\n      node.props &&\n      node.props.style &&\n      hasAnyDefined(style, INHERITABLE_FONT_STYLES)\n    ) {\n      // @ts-ignore\n      const inheritableStyles = pick(style, INHERITABLE_FONT_STYLES);\n      context.addInheritableStyles(inheritableStyles);\n    }\n\n    // Handle Text Children\n    const textNodes = computeTextTree(node, context);\n    yogaNode.setMeasureFunc(createStringMeasurer(bridge)(textNodes));\n\n    return { node: yogaNode, stop: true };\n  }\n\n  return { node: yogaNode };\n};\n"
  },
  {
    "path": "src/jsonUtils/computeYogaTree.ts",
    "content": "import yoga from 'yoga-layout-prebuilt';\nimport { ReactTestRendererNode } from 'react-test-renderer';\nimport { PlatformBridge } from '../types';\nimport { computeYogaNode } from './computeYogaNode';\nimport { Context } from '../utils/Context';\nimport { zIndex } from '../utils/zIndex';\n\nconst walkTree = (bridge: PlatformBridge) => (tree: ReactTestRendererNode, context: Context) => {\n  const { node, stop } = computeYogaNode(bridge)(tree, context);\n\n  if (typeof tree === 'string' || tree.type === 'sketch_svg') {\n    // handle svg node, eg: stop here, we will handle the children in the renderer\n    return node;\n  }\n\n  if (tree.children && tree.children.length > 0) {\n    // Calculates zIndex order\n    const children = zIndex(tree.children);\n\n    for (let index = 0; index < children.length; index += 1) {\n      const childComponent = children[index];\n      // Avoid going into <text> node's children\n      if (!stop) {\n        const childNode = walkTree(bridge)(childComponent, context.forChildren());\n        node.insertChild(childNode, index);\n      }\n    }\n  }\n\n  return node;\n};\n\nexport const computeYogaTree = (bridge: PlatformBridge) => (\n  root: ReactTestRendererNode,\n  context: Context,\n): yoga.YogaNode => walkTree(bridge)(root, context);\n"
  },
  {
    "path": "src/jsonUtils/hotspotLayer.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\n\nimport { generateID } from './models';\n\nconst animationTypes = {\n  none: -1,\n  slideFromRight: 0,\n  slideFromLeft: 1,\n  slideFromBottom: 2,\n  slideFromTop: 3,\n};\n\nconst BackTarget = 'back';\n\nconst getArtboard = (target: string) => {\n  if (target === BackTarget) {\n    return BackTarget;\n  }\n  return generateID(`artboard:${target}`, true);\n};\n\nexport const hotspotLayer = ({\n  targetId,\n  target,\n  animationType,\n}: {\n  targetId?: string;\n  target?: string;\n  animationType?: 'none' | 'slideFromRight' | 'slideFromLeft' | 'slideFromBottom' | 'slideFromTop';\n}): { flow: FileFormat.FlowConnection } => ({\n  flow: {\n    _class: 'MSImmutableFlowConnection',\n    animationType: (animationType && animationTypes[animationType]) || -1,\n    destinationArtboardID: target ? getArtboard(target) : targetId || 'broken',\n  },\n});\n"
  },
  {
    "path": "src/jsonUtils/layerGroup.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport { makeResizeConstraint } from './resizeConstraint';\nimport { generateID, makeRect } from './models';\nimport { ResizeConstraints } from '../types';\nimport { makeStyle } from './style';\n\nexport const layerGroup = (\n  x: number,\n  y: number,\n  width: number,\n  height: number,\n  opacity: number,\n  resizingConstraint?: ResizeConstraints,\n): FileFormat.Group => ({\n  _class: 'group',\n  do_objectID: generateID(),\n  exportOptions: {\n    _class: 'exportOptions',\n    exportFormats: [],\n    includedLayerIds: [],\n    layerOptions: 0,\n    shouldTrim: false,\n  },\n  frame: makeRect(x, y, width, height),\n  isFlippedHorizontal: false,\n  isFlippedVertical: false,\n  isLocked: false,\n  isVisible: true,\n  layerListExpandedType: FileFormat.LayerListExpanded.Expanded,\n  name: 'Group',\n  nameIsFixed: false,\n  resizingConstraint: makeResizeConstraint(resizingConstraint),\n  resizingType: FileFormat.ResizeType.Stretch,\n  rotation: 0,\n  shouldBreakMaskChain: false,\n  style: makeStyle({ opacity }),\n  hasClickThrough: false,\n  layers: [],\n  booleanOperation: FileFormat.BooleanOperation.NA,\n  isFixedToViewport: false,\n});\n"
  },
  {
    "path": "src/jsonUtils/makeSvgLayer/graphics/curvePoint.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport { Point } from './types';\n\nexport function describePoint(point: Point): string {\n  const { x, y } = point;\n  return `{${x}, ${y}}`;\n}\n\nexport function makeCurvePoint(\n  point: Point,\n  curveFrom?: Point,\n  curveTo?: Point,\n  curveMode?: FileFormat.CurveMode,\n): FileFormat.CurvePoint {\n  return {\n    _class: 'curvePoint',\n    cornerRadius: 0,\n    curveFrom: describePoint(curveFrom || point),\n    curveMode: curveMode || 0,\n    curveTo: describePoint(curveTo || point),\n    hasCurveFrom: !!curveFrom,\n    hasCurveTo: !!curveTo,\n    point: describePoint(point),\n  };\n}\n"
  },
  {
    "path": "src/jsonUtils/makeSvgLayer/graphics/path.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\n\nimport { normalizePointInRect } from './point';\nimport { makeCurvePoint, describePoint } from './curvePoint';\n\ntype Path = Pick<FileFormat.ShapePath, 'isClosed' | 'points'>;\n\nfunction makePath(curvePoints: FileFormat.CurvePoint[], isClosed: boolean): Path {\n  return {\n    isClosed,\n    points: curvePoints,\n  };\n}\n\n// Points are normalized between 0 and 1, relative to the frame.\n// We use the original frame here and can scale it later.\n//\n// This is a rough port of Lona's PDF to Sketch path conversion\n// https://github.com/airbnb/Lona/blob/94fd0b26de3e3f4b4496cdaa4ab31c6d258dc4ac/studio/LonaStudio/Utils/Sketch.swift#L285\nexport function makePathsFromCommands(\n  commands: { type: string; data: any }[],\n  frame: FileFormat.Rect,\n): Path[] {\n  const paths: Path[] = [];\n  let curvePoints: FileFormat.CurvePoint[] = [];\n\n  function finishPath(isClosed: boolean) {\n    if (curvePoints.length === 0) return;\n\n    const path = makePath(curvePoints, isClosed);\n    paths.push(path);\n\n    curvePoints = [];\n  }\n\n  commands.forEach((command: any) => {\n    const { type, data } = command;\n\n    switch (type) {\n      case 'move': {\n        finishPath(false);\n\n        const { to } = data;\n        const curvePoint = makeCurvePoint(normalizePointInRect(to, frame), undefined, undefined, 1);\n        curvePoints.push(curvePoint);\n        break;\n      }\n      case 'line': {\n        const { to } = data;\n        const curvePoint = makeCurvePoint(normalizePointInRect(to, frame), undefined, undefined, 1);\n        curvePoints.push(curvePoint);\n        break;\n      }\n      case 'cubicCurve': {\n        const { to, controlPoint1, controlPoint2 } = data;\n\n        if (curvePoints.length > 0) {\n          const last = curvePoints[curvePoints.length - 1];\n          last.curveFrom = describePoint(normalizePointInRect(controlPoint1, frame));\n          last.curveMode = 2;\n          last.hasCurveFrom = true;\n        }\n\n        const curvePoint = makeCurvePoint(\n          normalizePointInRect(to, frame),\n          undefined,\n          normalizePointInRect(controlPoint2, frame),\n          2,\n        );\n\n        curvePoints.push(curvePoint);\n        break;\n      }\n      case 'close': {\n        // If first and last points are equal, combine them\n        if (curvePoints.length > 0) {\n          const first = curvePoints[0];\n          const last = curvePoints[curvePoints.length - 1];\n\n          if (first.point == last.point && last.hasCurveTo) {\n            first.curveTo = last.curveTo;\n            first.hasCurveTo = last.hasCurveTo;\n            first.curveMode = 2;\n\n            curvePoints.pop();\n          }\n        }\n\n        finishPath(true);\n        break;\n      }\n      default:\n        throw new Error(`Invalid SVG path command: ${type}`);\n    }\n  });\n\n  finishPath(false);\n\n  return paths;\n}\n\nexport function makeLineCapStyle(strokeLineCap: 'butt' | 'round' | 'square'): 0 | 1 | 2 {\n  switch (strokeLineCap) {\n    case 'butt':\n      return 0;\n    case 'round':\n      return 1;\n    case 'square':\n      return 2;\n    default:\n      throw new Error(`Invalid SVG stroke line cap: ${strokeLineCap}`);\n  }\n}\n"
  },
  {
    "path": "src/jsonUtils/makeSvgLayer/graphics/point.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport { Point } from './types';\n\nexport function normalizePointInRect(point: Point, rect: FileFormat.Rect): Point {\n  const x = (point.x - rect.x) / rect.width;\n  const y = (point.y - rect.y) / rect.height;\n  return { x, y };\n}\n"
  },
  {
    "path": "src/jsonUtils/makeSvgLayer/graphics/rect.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport { makeRect } from '../../models';\nimport { Point, Size } from './types';\n\nexport function makeBoundingRectFromPoints(points: Point[]): FileFormat.Rect {\n  const x = Math.min(...points.map((point) => point.x));\n  const y = Math.min(...points.map((point) => point.y));\n  const width = Math.max(...points.map((point) => point.x)) - x;\n  const height = Math.max(...points.map((point) => point.y)) - y;\n\n  return makeRect(x, y, width, height);\n}\n\nexport function makeBoundingRectFromCommands(commands: any): FileFormat.Rect {\n  const points: Point[] = commands.reduce((acc: Point[], command: any) => {\n    const { type, data } = command;\n\n    switch (type) {\n      case 'line':\n      case 'move': {\n        const { to } = data;\n        return [...acc, to];\n      }\n      case 'cubicCurve': {\n        const { to, controlPoint1, controlPoint2 } = data;\n        return [...acc, to, controlPoint1, controlPoint2];\n      }\n      case 'close':\n        return acc;\n      default:\n        throw new Error(`Invalid SVG path command: ${type}`);\n    }\n  }, []);\n\n  return makeBoundingRectFromPoints(points);\n}\n\nexport function unionRects(...rects: FileFormat.Rect[]): FileFormat.Rect {\n  function union(a: FileFormat.Rect, b: FileFormat.Rect) {\n    const minX = Math.min(a.x, b.x);\n    const minY = Math.min(a.y, b.y);\n    const maxX = Math.max(a.x + a.width, b.x + b.width);\n    const maxY = Math.max(a.y + a.height, b.y + b.height);\n\n    return makeRect(minX, minY, maxX - minX, maxY - minY);\n  }\n\n  if (rects.length === 0) {\n    throw new Error('No rects to union');\n  }\n\n  return rects.reduce((acc, rect) => union(acc, rect), rects[0]);\n}\n\nexport function scaleRect(rect: FileFormat.Rect, scale: number) {\n  return makeRect(rect.x * scale, rect.y * scale, rect.width * scale, rect.height * scale);\n}\n\n// Port of Lona's resizing algorithm\n// https://github.com/airbnb/Lona/blob/94fd0b26de3e3f4b4496cdaa4ab31c6d258dc4ac/examples/generated/test/swift/CGSize%2BResizing.swift\nexport function resize(\n  source: Size,\n  destination: Size,\n  resizingMode: 'cover' | 'contain' | 'stretch',\n) {\n  const newSize = { ...destination };\n\n  const sourceAspectRatio = source.height / source.width;\n  const destinationAspectRatio = destination.height / destination.width;\n\n  const sourceIsWiderThanDestination = sourceAspectRatio < destinationAspectRatio;\n\n  switch (resizingMode) {\n    case 'contain':\n      if (sourceIsWiderThanDestination) {\n        newSize.height = destination.width * sourceAspectRatio;\n      } else {\n        newSize.width = destination.height / sourceAspectRatio;\n      }\n      break;\n    case 'cover':\n      if (sourceIsWiderThanDestination) {\n        newSize.width = destination.height / sourceAspectRatio;\n      } else {\n        newSize.height = destination.width * sourceAspectRatio;\n      }\n      break;\n    case 'stretch':\n      break;\n    default:\n      throw new Error('Invalid resizing mode');\n  }\n\n  return makeRect(\n    (destination.width - newSize.width) / 2.0,\n    (destination.height - newSize.height) / 2.0,\n    newSize.width,\n    newSize.height,\n  );\n}\n"
  },
  {
    "path": "src/jsonUtils/makeSvgLayer/graphics/types.ts",
    "content": "export type Point = { x: number; y: number };\nexport type Size = { width: number; height: number };\n"
  },
  {
    "path": "src/jsonUtils/makeSvgLayer/index.sketch.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport { toSJSON } from '../sketchJson/toSJSON';\n\nimport { LayoutInfo } from '../../types';\n\nexport function makeSvgLayer(_layout: LayoutInfo, name: string, svg: string): FileFormat.Group {\n  const svgString = NSString.stringWithString(svg);\n  const svgData = svgString.dataUsingEncoding(NSUTF8StringEncoding);\n  const svgImporter = MSSVGImporter.svgImporter();\n  svgImporter.prepareToImportFromData(svgData);\n\n  const frame = NSMakeRect(0, 0, svgImporter.graph().width(), svgImporter.graph().height());\n  const root = MSLayerGroup.alloc().initWithFrame(frame);\n  root.name = name;\n\n  svgImporter.graph().makeLayerWithParentLayer_progress(root, null);\n  root.ungroupSingleChildDescendentGroups();\n  svgImporter.scale_rootGroup(svgImporter.importer().scaleValue(), root);\n\n  return toSJSON(root) as FileFormat.Group;\n}\n"
  },
  {
    "path": "src/jsonUtils/makeSvgLayer/index.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport svgModel from '@lona/svg-model';\nimport { LayoutInfo, ViewStyle } from '../../types';\nimport { makeShapeGroup, makeShapePath } from '../shapeLayers';\nimport { makeRect } from '../models';\nimport { createUniformBorder } from '../borders';\nimport { layerGroup } from '../layerGroup';\nimport { makePathsFromCommands, makeLineCapStyle } from './graphics/path';\nimport { unionRects, scaleRect, makeBoundingRectFromCommands, resize } from './graphics/rect';\n\nfunction makeLayerFromPathElement(pathElement: any, _parentFrame: FileFormat.Rect, scale: number) {\n  const {\n    data: {\n      params: { commands, style },\n    },\n  } = pathElement;\n\n  // Paths are created using the original frame\n  const pathFrame = makeBoundingRectFromCommands(commands);\n  const paths = makePathsFromCommands(commands, pathFrame);\n\n  // Scale the frame to fill the viewBox\n  const shapeGroupFrame = scaleRect(pathFrame, scale);\n\n  // Each shape path has an origin of {0, 0}, since the shapeGroup layer stores the real origin,\n  // and we don't want to apply the origin translation twice.\n  const shapePathFrame = makeRect(0, 0, shapeGroupFrame.width, shapeGroupFrame.height);\n\n  const shapePaths = paths.map((path) => makeShapePath(shapePathFrame, path));\n\n  const viewStyle: ViewStyle = {};\n\n  if (style.fill) {\n    viewStyle.backgroundColor = style.fill;\n  }\n\n  const shapeGroup = makeShapeGroup(shapeGroupFrame, shapePaths, viewStyle);\n\n  if (style.stroke && shapeGroup.style) {\n    const lineCap = makeLineCapStyle(style.strokeLineCap);\n    const borderStyle = createUniformBorder(\n      style.strokeWidth * scale,\n      style.stroke,\n      undefined,\n      FileFormat.BorderPosition.Center,\n      lineCap,\n      lineCap,\n    );\n    shapeGroup.style = { ...shapeGroup.style, ...borderStyle };\n  }\n\n  return shapeGroup;\n}\n\nfunction makeLayerGroup(\n  frame: FileFormat.Rect,\n  layers: (\n    | FileFormat.Group\n    | FileFormat.Oval\n    | FileFormat.Polygon\n    | FileFormat.Rectangle\n    | FileFormat.ShapePath\n    | FileFormat.Star\n    | FileFormat.Triangle\n    | FileFormat.ShapeGroup\n    | FileFormat.Text\n    | FileFormat.SymbolMaster\n    | FileFormat.SymbolInstance\n    | FileFormat.Slice\n    | FileFormat.Hotspot\n    | FileFormat.Bitmap\n  )[],\n  name: string,\n) {\n  const group = layerGroup(frame.x, frame.y, frame.width, frame.height, 1);\n  group.name = name;\n  group.layers = layers;\n  return group;\n}\n\nexport function makeSvgLayer(layout: LayoutInfo, name: string, svg: string) {\n  const {\n    data: { params, children },\n  } = svgModel(svg);\n\n  const {\n    viewBox = {\n      x: layout.left,\n      y: layout.top,\n      width: layout.width,\n      height: layout.height,\n    },\n  } = params;\n\n  // Determine the rect to generate layers within\n  const croppedRect = resize(viewBox, layout, 'contain');\n  const scale = croppedRect.width / viewBox.width;\n\n  // The top-level frame is the union of every path within\n  const frame = unionRects(\n    ...children.map((pathElement: any) =>\n      makeBoundingRectFromCommands(pathElement.data.params.commands),\n    ),\n  );\n\n  // Scale the frame to fill the viewBox\n  const scaledFrame = scaleRect(frame, scale);\n\n  const layers = children.map((element: any) =>\n    makeLayerFromPathElement(element, scaledFrame, scale),\n  );\n  return makeLayerGroup(croppedRect, layers, name);\n}\n"
  },
  {
    "path": "src/jsonUtils/models.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport seedrandom from 'seedrandom';\nimport normalizeColor, { rgba } from 'normalize-css-color';\nimport { Color, ResizeConstraints } from '../types';\nimport { makeResizeConstraint } from './resizeConstraint';\n\nconst lut: string[] = [];\nfor (let i = 0; i < 256; i += 1) {\n  lut[i] = (i < 16 ? '0' : '') + i.toString(16);\n}\n// Hack (http://stackoverflow.com/a/21963136)\nfunction e7(seed?: string) {\n  const random = seed ? seedrandom(`${seed}0`) : Math.random;\n  const d0 = (random() * 0xffffffff) | 0;\n  const d1 = (random() * 0xffffffff) | 0;\n  const d2 = (random() * 0xffffffff) | 0;\n  const d3 = (random() * 0xffffffff) | 0;\n  return `${\n    lut[d0 & 0xff] + lut[(d0 >> 8) & 0xff] + lut[(d0 >> 16) & 0xff] + lut[(d0 >> 24) & 0xff]\n  }-${lut[d1 & 0xff]}${lut[(d1 >> 8) & 0xff]}-${lut[((d1 >> 16) & 0x0f) | 0x40]}${\n    lut[(d1 >> 24) & 0xff]\n  }-${lut[(d2 & 0x3f) | 0x80]}${lut[(d2 >> 8) & 0xff]}-${lut[(d2 >> 16) & 0xff]}${\n    lut[(d2 >> 24) & 0xff]\n  }${lut[d3 & 0xff]}${lut[(d3 >> 8) & 0xff]}${lut[(d3 >> 16) & 0xff]}${lut[(d3 >> 24) & 0xff]}`;\n}\n\n// Keep track on previous numbers that are generated\nlet previousNumber = 1;\n\n// Will always produce a unique Number (Int) based on of the current date\nfunction generateIdNumber() {\n  let date = Date.now();\n\n  if (date <= previousNumber) {\n    previousNumber += 1;\n    date = previousNumber;\n  } else {\n    previousNumber = date;\n  }\n\n  return date;\n}\n\n// Keep track of previous seeds\nconst previousSeeds: { [seed: string]: number } = {};\n\nexport function generateID(seed?: string, hardcoded?: boolean): string {\n  let _seed = seed;\n\n  if (seed) {\n    if (!previousSeeds[seed]) {\n      previousSeeds[seed] = 0;\n    }\n    previousSeeds[seed] += 1;\n\n    if (!hardcoded) {\n      _seed = `${seed}${previousSeeds[seed]}`;\n    }\n  }\n\n  return e7(_seed);\n}\n\nconst safeToLower = (input: Color): Color => {\n  if (typeof input === 'string') {\n    return input.toLowerCase();\n  }\n\n  return input;\n};\n\n// Takes colors as CSS hex, name, rgb, rgba, hsl or hsla\nexport const makeColorFromCSS = (input: Color, alpha: number = 1): FileFormat.Color => {\n  const nullableColor = normalizeColor(safeToLower(input));\n  const colorInt: number = nullableColor == null ? 0x00000000 : nullableColor;\n  const { r, g, b, a } = rgba(colorInt);\n\n  return {\n    _class: 'color',\n    red: r / 255,\n    green: g / 255,\n    blue: b / 255,\n    alpha: a * alpha,\n  };\n};\n\nexport const emptyGradient: FileFormat.Gradient = {\n  _class: 'gradient',\n  elipseLength: 0,\n  from: '{0.5, 0}',\n  gradientType: 0,\n  to: '{0.5, 1}',\n  stops: [\n    {\n      _class: 'gradientStop',\n      position: 0,\n      color: {\n        _class: 'color',\n        alpha: 1,\n        blue: 1,\n        green: 1,\n        red: 1,\n      },\n    },\n    {\n      _class: 'gradientStop',\n      position: 1,\n      color: {\n        _class: 'color',\n        alpha: 1,\n        blue: 0,\n        green: 0,\n        red: 0,\n      },\n    },\n  ],\n};\n\n// Solid color fill\nexport const makeColorFill = (cssColor: Color): FileFormat.Fill => ({\n  _class: 'fill',\n  isEnabled: true,\n  color: makeColorFromCSS(cssColor),\n  fillType: FileFormat.FillType.Color,\n  noiseIndex: 0,\n  noiseIntensity: 0,\n  patternFillType: FileFormat.PatternFillType.Fill,\n  patternTileScale: 1,\n  contextSettings: {\n    _class: 'graphicsContextSettings',\n    blendMode: FileFormat.BlendMode.Normal,\n    opacity: 1,\n  },\n  gradient: emptyGradient,\n});\n\nexport const makeImageFill = (\n  image: FileFormat.ImageDataRef,\n  patternFillType: FileFormat.PatternFillType = FileFormat.PatternFillType.Fill,\n): FileFormat.Fill => ({\n  _class: 'fill',\n  isEnabled: true,\n  fillType: FileFormat.FillType.Pattern,\n  color: makeColorFromCSS('white'),\n  image,\n  noiseIndex: 0,\n  noiseIntensity: 0,\n  patternFillType,\n  patternTileScale: 1,\n  contextSettings: {\n    _class: 'graphicsContextSettings',\n    blendMode: FileFormat.BlendMode.Normal,\n    opacity: 1,\n  },\n  gradient: emptyGradient,\n});\n\n// Used in frames, etc\nexport const makeRect = (x: number, y: number, width: number, height: number): FileFormat.Rect => ({\n  _class: 'rect',\n  constrainProportions: false,\n  x,\n  y,\n  width,\n  height,\n});\n\nexport const makeJSONDataReference = (image: {\n  data: string;\n  sha1: string;\n}): FileFormat.ImageDataRef => ({\n  _class: 'MSJSONOriginalDataReference',\n  _ref: `images/${generateID()}`,\n  _ref_class: 'MSImageData',\n  data: {\n    _data: image.data,\n    // TODO(gold): can I just declare this as a var instead of using Cocoa?\n  },\n  sha1: {\n    _data: image.sha1,\n  },\n});\n\nexport const makeOverride = (\n  path: string,\n  type: 'symbolID' | 'stringValue' | 'layerStyle' | 'textStyle' | 'flowDestination' | 'image',\n  value: string | FileFormat.ImageDataRef,\n): FileFormat.OverrideValue => ({\n  _class: 'overrideValue',\n  do_objectID: generateID(),\n  overrideName: `${path}_${type}`,\n  // @ts-ignore https://github.com/sketch-hq/sketch-file-format-ts/issues/9\n  value,\n});\n\nexport const makeSymbolInstance = (\n  frame: FileFormat.Rect,\n  symbolID: string,\n  name: string,\n  resizingConstraint?: ResizeConstraints | null,\n): FileFormat.SymbolInstance => ({\n  _class: 'symbolInstance',\n  horizontalSpacing: 0,\n  verticalSpacing: 0,\n  nameIsFixed: true,\n  isVisible: true,\n  do_objectID: generateID(`symbolInstance:${name}:${symbolID}`),\n  resizingConstraint: makeResizeConstraint(resizingConstraint),\n  name,\n  symbolID,\n  frame,\n  booleanOperation: FileFormat.BooleanOperation.NA,\n  isLocked: false,\n  isFixedToViewport: false,\n  isFlippedHorizontal: false,\n  isFlippedVertical: false,\n  layerListExpandedType: FileFormat.LayerListExpanded.Undecided,\n  resizingType: FileFormat.ResizeType.Stretch,\n  rotation: 0,\n  shouldBreakMaskChain: false,\n  overrideValues: [],\n  scale: 1,\n  exportOptions: {\n    _class: 'exportOptions',\n    exportFormats: [],\n    includedLayerIds: [],\n    layerOptions: 0,\n    shouldTrim: false,\n  },\n});\n\nexport const makeSymbolMaster = (\n  frame: FileFormat.Rect,\n  symbolID: string,\n  name: string,\n): FileFormat.SymbolMaster => ({\n  _class: 'symbolMaster',\n  do_objectID: generateID(`symbolMaster:${name}`, !!name),\n  nameIsFixed: true,\n  isVisible: true,\n  backgroundColor: makeColorFromCSS('white'),\n  hasBackgroundColor: false,\n  name,\n  changeIdentifier: generateIdNumber(),\n  symbolID,\n  frame,\n  booleanOperation: FileFormat.BooleanOperation.NA,\n  isLocked: false,\n  isFixedToViewport: false,\n  isFlippedHorizontal: false,\n  isFlippedVertical: false,\n  layerListExpandedType: FileFormat.LayerListExpanded.Undecided,\n  resizingType: FileFormat.ResizeType.Stretch,\n  rotation: 0,\n  shouldBreakMaskChain: false,\n  exportOptions: {\n    _class: 'exportOptions',\n    exportFormats: [],\n    includedLayerIds: [],\n    layerOptions: 0,\n    shouldTrim: false,\n  },\n  resizingConstraint: makeResizeConstraint(),\n  hasClickThrough: false,\n  layers: [],\n  horizontalRulerData: {\n    _class: 'rulerData',\n    base: 0,\n    guides: [],\n  },\n  verticalRulerData: {\n    _class: 'rulerData',\n    base: 0,\n    guides: [],\n  },\n  includeInCloudUpload: true,\n  includeBackgroundColorInExport: false,\n  includeBackgroundColorInInstance: false,\n  isFlowHome: false,\n  resizesContent: false,\n  allowsOverrides: true,\n  overrideProperties: [],\n});\n"
  },
  {
    "path": "src/jsonUtils/resizeConstraint.ts",
    "content": "import { ResizeConstraints } from '../types';\n\n/*\n  RESIZE CONSTRAINT RULES\n\n  Order of properties as map keys:\n  1. top\n  2. right\n  3. bottom\n  4: left\n  5. fixedHeight\n  6. fixedWidth\n */\n\nconst RESIZE_CONSTRAINTS: { [key: string]: number } = {\n  top_left_fixedHeight_fixedWidth: 9,\n  top_right_left_fixedHeight: 10,\n  top_left_fixedHeight: 11,\n  top_right_fixedHeight_fixedWidth: 12,\n  top_fixedHeight_fixedWidth: 13,\n  top_right_fixedHeight: 14,\n  top_fixedHeight: 15,\n  top_bottom_left_fixedWidth: 17,\n  top_right_bottom_left: 18,\n  top_bottom_left: 19,\n  top_right_bottom_fixedWidth: 20,\n  top_bottom_fixedWidth: 21,\n  top_right_bottom: 22,\n  top_bottom: 23,\n  top_left_fixedWidth: 25,\n  top_right_left: 26,\n  top_left: 27,\n  top_right_fixedWidth: 28,\n  top_fixedWidth: 29,\n  top_right: 30,\n  top: 31,\n  bottom_left_fixedHeight_fixedWidth: 33,\n  right_bottom_left_fixedHeight: 34,\n  bottom_left_fixedHeight: 35,\n  right_bottom_fixedHeight_fixedWidth: 36,\n  bottom_fixedHeight_fixedWidth: 37,\n  right_bottom_fixedHeight: 38,\n  bottom_fixedHeight: 39,\n  left_fixedHeight_fixedWidth: 41,\n  right_left_fixedHeight: 42,\n  left_fixedHeight: 43,\n  right_fixedHeight_fixedWidth: 44,\n  fixedHeight_fixedWidth: 45,\n  right_fixedHeight: 46,\n  fixedHeight: 47,\n  bottom_left_fixedWidth: 49,\n  right_bottom_left: 50,\n  bottom_left: 51,\n  right_bottom_fixedWidth: 52,\n  bottom_fixedWidth: 53,\n  right_bottom: 54,\n  bottom: 55,\n  left_fixedWidth: 57,\n  right_left: 58,\n  left: 59,\n  right_fixedWidth: 60,\n  fixedWidth: 61,\n  right: 62,\n  none: 63,\n};\n\nexport function makeResizeConstraint(resizingConstraint?: ResizeConstraints | null): number {\n  if (resizingConstraint) {\n    const constraints = [];\n    const { top, right, bottom, left, fixedHeight, fixedWidth } = resizingConstraint;\n\n    if (top) {\n      constraints.push('top');\n    }\n    if (right) {\n      constraints.push('right');\n    }\n    if (bottom) {\n      constraints.push('bottom');\n    }\n    if (left) {\n      constraints.push('left');\n    }\n    if (fixedHeight) {\n      constraints.push('fixedHeight');\n    }\n    if (fixedWidth) {\n      constraints.push('fixedWidth');\n    }\n\n    if (constraints.length > 0) {\n      const constraint = RESIZE_CONSTRAINTS[constraints.join('_')];\n      if (!constraint) {\n        throw new Error(\n          `\\n${JSON.stringify(\n            resizingConstraint,\n            null,\n            2,\n          )}\\nconstraint is not a valid combination.`,\n        );\n      }\n      return constraint;\n    }\n  }\n\n  return RESIZE_CONSTRAINTS.none; // No constraints\n}\n"
  },
  {
    "path": "src/jsonUtils/shapeLayers.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport { makeResizeConstraint } from './resizeConstraint';\nimport { generateID, makeRect, makeColorFromCSS, emptyGradient } from './models';\nimport { makeStyle } from './style';\nimport { Color, ResizeConstraints, ViewStyle } from '../types';\n\ntype Radii = (number | null)[];\n\nexport const makeHorizontalPath = (): Pick<FileFormat.ShapePath, 'isClosed' | 'points'> => ({\n  isClosed: false,\n  points: [\n    {\n      _class: 'curvePoint',\n      cornerRadius: 0,\n      curveFrom: '{0, 0}',\n      curveMode: FileFormat.CurveMode.Straight,\n      curveTo: '{0, 0}',\n      hasCurveFrom: false,\n      hasCurveTo: false,\n      point: '{0, 0.5}',\n    },\n    {\n      _class: 'curvePoint',\n      cornerRadius: 0,\n      curveFrom: '{0, 0}',\n      curveMode: FileFormat.CurveMode.Straight,\n      curveTo: '{0, 0}',\n      hasCurveFrom: false,\n      hasCurveTo: false,\n      point: '{1, 0.5}',\n    },\n  ],\n});\n\nexport const makeVerticalPath = (): Pick<FileFormat.ShapePath, 'isClosed' | 'points'> => ({\n  isClosed: false,\n  points: [\n    {\n      _class: 'curvePoint',\n      cornerRadius: 0,\n      curveFrom: '{0, 0}',\n      curveMode: FileFormat.CurveMode.Straight,\n      curveTo: '{0, 0}',\n      hasCurveFrom: false,\n      hasCurveTo: false,\n      point: '{0.5, 0}',\n    },\n    {\n      _class: 'curvePoint',\n      cornerRadius: 0,\n      curveFrom: '{0, 0}',\n      curveMode: FileFormat.CurveMode.Straight,\n      curveTo: '{0, 0}',\n      hasCurveFrom: false,\n      hasCurveTo: false,\n      point: '{0.5, 1}',\n    },\n  ],\n});\n\nexport const makeRectPath = (\n  radii: Radii = [0, 0, 0, 0],\n): Pick<FileFormat.ShapePath, 'isClosed' | 'points'> => {\n  const [r0, r1, r2, r3] = radii;\n  return {\n    isClosed: true,\n    points: [\n      {\n        _class: 'curvePoint',\n        cornerRadius: r0 || 0,\n        curveFrom: '{0, 0}',\n        curveMode: FileFormat.CurveMode.Straight,\n        curveTo: '{0, 0}',\n        hasCurveFrom: false,\n        hasCurveTo: false,\n        point: '{0, 0}',\n      },\n      {\n        _class: 'curvePoint',\n        cornerRadius: r1 || 0,\n        curveFrom: '{1, 0}',\n        curveMode: FileFormat.CurveMode.Straight,\n        curveTo: '{1, 0}',\n        hasCurveFrom: false,\n        hasCurveTo: false,\n        point: '{1, 0}',\n      },\n      {\n        _class: 'curvePoint',\n        cornerRadius: r2 || 0,\n        curveFrom: '{1, 1}',\n        curveMode: FileFormat.CurveMode.Straight,\n        curveTo: '{1, 1}',\n        hasCurveFrom: false,\n        hasCurveTo: false,\n        point: '{1, 1}',\n      },\n      {\n        _class: 'curvePoint',\n        cornerRadius: r3 || 0,\n        curveFrom: '{0, 1}',\n        curveMode: FileFormat.CurveMode.Straight,\n        curveTo: '{0, 1}',\n        hasCurveFrom: false,\n        hasCurveTo: false,\n        point: '{0, 1}',\n      },\n    ],\n  };\n};\n\nexport const makeShapePath = (\n  frame: FileFormat.Rect,\n  path: Pick<FileFormat.ShapePath, 'isClosed' | 'points'>,\n  resizingConstraint?: ResizeConstraints,\n): FileFormat.ShapePath => ({\n  _class: 'shapePath',\n  frame,\n  do_objectID: generateID(),\n  isFlippedHorizontal: false,\n  isFlippedVertical: false,\n  isLocked: false,\n  isVisible: true,\n  layerListExpandedType: FileFormat.LayerListExpanded.Undecided,\n  name: 'Path',\n  nameIsFixed: false,\n  resizingConstraint: makeResizeConstraint(resizingConstraint),\n  resizingType: FileFormat.ResizeType.Stretch,\n  rotation: 0,\n  shouldBreakMaskChain: false,\n  booleanOperation: FileFormat.BooleanOperation.NA,\n  edited: false,\n  ...path,\n  isFixedToViewport: false,\n  pointRadiusBehaviour: FileFormat.PointsRadiusBehaviour.Rounded,\n  exportOptions: {\n    _class: 'exportOptions',\n    exportFormats: [],\n    includedLayerIds: [],\n    layerOptions: 0,\n    shouldTrim: false,\n  },\n});\n\nexport const makeRectShapeLayer = (\n  x: number,\n  y: number,\n  width: number,\n  height: number,\n  radii: Radii = [0, 0, 0, 0],\n  resizingConstraint?: ResizeConstraints | null,\n): FileFormat.Rectangle => {\n  const fixedRadius = radii[0] || 0;\n  const path = makeRectPath(radii);\n  return {\n    ...path,\n    _class: 'rectangle',\n    do_objectID: generateID(),\n    frame: makeRect(x, y, width, height),\n    isFlippedHorizontal: false,\n    isFlippedVertical: false,\n    isLocked: false,\n    isVisible: true,\n    layerListExpandedType: FileFormat.LayerListExpanded.Undecided,\n    name: 'Path',\n    nameIsFixed: false,\n    resizingConstraint: makeResizeConstraint(resizingConstraint),\n    resizingType: FileFormat.ResizeType.Stretch,\n    rotation: 0,\n    shouldBreakMaskChain: false,\n    booleanOperation: FileFormat.BooleanOperation.NA,\n    edited: false,\n    fixedRadius,\n    hasConvertedToNewRoundCorners: true,\n    isFixedToViewport: false,\n    pointRadiusBehaviour: FileFormat.PointsRadiusBehaviour.Rounded,\n    exportOptions: {\n      _class: 'exportOptions',\n      exportFormats: [],\n      includedLayerIds: [],\n      layerOptions: 0,\n      shouldTrim: false,\n    },\n  };\n};\n\nexport const makeShapeGroup = (\n  frame: FileFormat.Rect,\n  layers: (\n    | FileFormat.ShapePath\n    | FileFormat.Rectangle\n    | FileFormat.SymbolMaster\n    | FileFormat.Group\n    | FileFormat.Polygon\n    | FileFormat.Star\n    | FileFormat.Triangle\n    | FileFormat.ShapeGroup\n    | FileFormat.Text\n    | FileFormat.SymbolInstance\n    | FileFormat.Slice\n    | FileFormat.Hotspot\n    | FileFormat.Bitmap\n  )[] = [],\n  style?: ViewStyle,\n  shadows?: (ViewStyle | undefined | null)[] | null,\n  fills?: FileFormat.Fill[],\n  resizingConstraint?: ResizeConstraints,\n): FileFormat.ShapeGroup => ({\n  _class: 'shapeGroup',\n  do_objectID: generateID(),\n  frame,\n  isLocked: false,\n  isVisible: true,\n  name: 'ShapeGroup',\n  nameIsFixed: false,\n  resizingConstraint: makeResizeConstraint(resizingConstraint),\n  resizingType: FileFormat.ResizeType.Stretch,\n  rotation: 0,\n  shouldBreakMaskChain: false,\n  style: makeStyle(style, fills, shadows),\n  hasClickThrough: false,\n  layers,\n  clippingMaskMode: 0,\n  hasClippingMask: false,\n  windingRule: FileFormat.WindingRule.EvenOdd,\n  isFixedToViewport: false,\n  exportOptions: {\n    _class: 'exportOptions',\n    exportFormats: [],\n    includedLayerIds: [],\n    layerOptions: 0,\n    shouldTrim: false,\n  },\n  isFlippedHorizontal: false,\n  isFlippedVertical: false,\n  booleanOperation: FileFormat.BooleanOperation.NA,\n  layerListExpandedType: FileFormat.LayerListExpanded.Undecided,\n});\n\nexport const makeVerticalBorder = (\n  x: number,\n  y: number,\n  length: number,\n  thickness: number,\n  color: Color,\n): FileFormat.ShapeGroup => {\n  const frame = makeRect(x, y, thickness, length);\n  const shapeFrame = makeRect(0, 0, thickness, length);\n  const shapePath = makeShapePath(shapeFrame, makeVerticalPath());\n  const content = makeShapeGroup(frame, [shapePath]);\n  if (!content.style) {\n    return content;\n  }\n  content.style.borders = [\n    {\n      _class: 'border',\n      isEnabled: true,\n      color: makeColorFromCSS(color),\n      fillType: FileFormat.FillType.Color,\n      position: FileFormat.BorderPosition.Center,\n      thickness,\n      contextSettings: {\n        _class: 'graphicsContextSettings',\n        blendMode: FileFormat.BlendMode.Normal,\n        opacity: 1,\n      },\n      gradient: emptyGradient,\n    },\n  ];\n  return content;\n};\n\nexport const makeHorizontalBorder = (\n  x: number,\n  y: number,\n  length: number,\n  thickness: number,\n  color: Color,\n): FileFormat.ShapeGroup => {\n  const frame = makeRect(x, y, length, thickness);\n  const shapeFrame = makeRect(0, 0, length, thickness);\n  const shapePath = makeShapePath(shapeFrame, makeHorizontalPath());\n  const content = makeShapeGroup(frame, [shapePath]);\n  if (!content.style) {\n    return content;\n  }\n  content.style.borders = [\n    {\n      _class: 'border',\n      isEnabled: true,\n      color: makeColorFromCSS(color),\n      fillType: FileFormat.FillType.Color,\n      position: FileFormat.BorderPosition.Center,\n      thickness,\n      contextSettings: {\n        _class: 'graphicsContextSettings',\n        blendMode: FileFormat.BlendMode.Normal,\n        opacity: 1,\n      },\n      gradient: emptyGradient,\n    },\n  ];\n  return content;\n};\n"
  },
  {
    "path": "src/jsonUtils/sketchJson/fromSJSON.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport { SketchLayer } from '../../types';\n\n/*\nVersions based on discussion info: http://sketchplugins.com/d/316-sketch-version\n*/\n// Internal Sketch Version (ex: 95 => v47 and below)\nconst SKETCH_HIGHEST_COMPATIBLE_VERSION = '95';\n\n/**\n *  Takes a Sketch JSON tree and turns it into a native object. May throw on invalid data\n */\nexport function fromSJSON(\n  jsonTree: FileFormat.AnyLayer | FileFormat.AnyObject,\n  version = SKETCH_HIGHEST_COMPATIBLE_VERSION,\n): SketchLayer {\n  const err = MOPointer.alloc().init();\n  const unarchivedObjectFromDictionary =\n    MSJSONDictionaryUnarchiver.unarchivedObjectFromDictionary_asVersion_corruptionDetected_error ||\n    MSJSONDictionaryUnarchiver.unarchiveObjectFromDictionary_asVersion_corruptionDetected_error;\n  const decoded = unarchivedObjectFromDictionary(jsonTree, version, null, err);\n\n  if (err.value() !== null) {\n    console.error(err.value());\n    throw new Error(err.value());\n  }\n\n  const mutableClass = decoded.class().mutableClass();\n  return mutableClass.alloc().initWithImmutableModelObject(decoded);\n}\n"
  },
  {
    "path": "src/jsonUtils/sketchJson/toSJSON.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport { SketchLayer } from '../../types';\n\nexport function toSJSON(\n  sketchObject: SketchLayer,\n): FileFormat.AnyObject | FileFormat.AnyLayer | null {\n  if (!sketchObject) {\n    return null;\n  }\n  const imm = sketchObject.immutableModelObject();\n\n  const err = MOPointer.alloc().init();\n  const data = MSJSONDataArchiver.archiveStringWithRootObject_error(imm, err);\n\n  if (err.value() !== null) {\n    console.error(err.value());\n    throw new Error(err.value());\n  }\n\n  return data ? JSON.parse(data) : data;\n}\n"
  },
  {
    "path": "src/jsonUtils/style.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport { makeColorFromCSS, makeColorFill } from './models';\nimport { ViewStyle, TextStyle, BorderStyle } from '../types';\nimport { hasAnyDefined } from '../utils/hasAnyDefined';\nimport { DEFAULT_BORDER_STYLE } from './borders';\n\nconst DEFAULT_SHADOW_COLOR = '#000';\n\nconst SHADOW_STYLES = [\n  'shadowColor',\n  'shadowOffset',\n  'shadowOpacity',\n  'shadowRadius',\n  'shadowSpread',\n  'textShadowColor',\n  'textShadowOffset',\n  'textShadowOpacity',\n  'textShadowRadius',\n  'textShadowSpread',\n];\n\nconst makeDashPattern = (style: BorderStyle, width: number): number[] => {\n  switch (style) {\n    case 'dashed':\n      return [width * 3, width * 3];\n    case 'dotted':\n      return [width, width];\n    case 'solid':\n      return [];\n    default:\n      return [];\n  }\n};\n\nexport const makeBorderOptions = (\n  style: BorderStyle,\n  width: number,\n  lineCapStyle: FileFormat.LineCapStyle = FileFormat.LineCapStyle.Butt,\n  lineJoinStyle: FileFormat.LineJoinStyle = FileFormat.LineJoinStyle.Miter,\n): FileFormat.BorderOptions => ({\n  _class: 'borderOptions',\n  isEnabled: false,\n  dashPattern: makeDashPattern(style, width),\n  lineCapStyle,\n  lineJoinStyle,\n});\n\nexport const makeShadow = (\n  style: ViewStyle | TextStyle,\n): FileFormat.Shadow | FileFormat.InnerShadow => {\n  const opacity =\n    style.shadowOpacity !== undefined && style.shadowOpacity !== null\n      ? style.shadowOpacity\n      : 'textShadowOpacity' in style &&\n        style.textShadowOpacity !== undefined &&\n        style.textShadowOpacity !== null\n      ? style.textShadowOpacity\n      : 1;\n  const color =\n    style.shadowColor ||\n    ('textShadowColor' in style && style.textShadowColor) ||\n    DEFAULT_SHADOW_COLOR;\n  const radius =\n    style.shadowRadius !== undefined && style.shadowRadius !== null\n      ? style.shadowRadius\n      : 'textShadowRadius' in style &&\n        style.textShadowRadius !== undefined &&\n        style.textShadowRadius !== null\n      ? style.textShadowRadius\n      : 1;\n  const spread =\n    style.shadowSpread !== undefined && style.shadowSpread !== null\n      ? style.shadowSpread\n      : 'textShadowSpread' in style &&\n        style.textShadowSpread !== undefined &&\n        style.textShadowSpread !== null\n      ? style.textShadowSpread\n      : 1;\n  let { width: offsetX, height: offsetY } =\n    style.shadowOffset || ('textShadowOffset' in style && style.textShadowOffset) || {};\n\n  if (!offsetX) {\n    offsetX = 0;\n  }\n  if (!offsetY) {\n    offsetY = 0;\n  }\n\n  const commonProps = {\n    isEnabled: true,\n    blurRadius: radius,\n    color: makeColorFromCSS(color, opacity),\n    contextSettings: {\n      _class: 'graphicsContextSettings',\n      blendMode: FileFormat.BlendMode.Normal,\n      opacity: 1,\n    },\n    offsetX,\n    offsetY,\n    spread,\n  } as const;\n\n  if (style.shadowInner) {\n    return {\n      _class: 'innerShadow',\n      ...commonProps,\n    };\n  }\n\n  return {\n    _class: 'shadow',\n    ...commonProps,\n  };\n};\n\nexport const makeStyle = (\n  style?: ViewStyle | TextStyle,\n  fills?: FileFormat.Fill[],\n  shadowsProp?: (ViewStyle | undefined | null)[] | null,\n): FileFormat.Style => {\n  const json: FileFormat.Style = {\n    _class: 'style',\n    fills: [],\n    miterLimit: 10,\n    innerShadows: [],\n    shadows: [],\n    borderOptions: makeBorderOptions(DEFAULT_BORDER_STYLE, 0, 0, 0),\n    startMarkerType: FileFormat.MarkerType.OpenArrow,\n    endMarkerType: FileFormat.MarkerType.OpenArrow,\n    windingRule: FileFormat.WindingRule.EvenOdd,\n    colorControls: {\n      _class: 'colorControls',\n      isEnabled: false,\n      brightness: 1,\n      contrast: 1,\n      hue: 1,\n      saturation: 1,\n    },\n  };\n\n  if (fills && fills.length) {\n    json.fills = (json.fills || []).concat(fills);\n  }\n\n  if (!style) {\n    return json;\n  }\n\n  if (style.opacity) {\n    json.contextSettings = {\n      _class: 'graphicsContextSettings',\n      blendMode: FileFormat.BlendMode.Normal,\n      opacity: style.opacity,\n    };\n  }\n\n  if (style.backgroundColor) {\n    const fill = makeColorFill(style.backgroundColor);\n    (json.fills || []).unshift(fill);\n  }\n\n  if (hasAnyDefined(style, SHADOW_STYLES)) {\n    const shadow = [makeShadow(style)];\n    if (style.shadowInner) {\n      json.innerShadows = shadow as FileFormat.InnerShadow[];\n    } else {\n      json.shadows = shadow as FileFormat.Shadow[];\n    }\n  }\n\n  if (shadowsProp) {\n    shadowsProp.forEach((shadowStyle) => {\n      if (!shadowStyle) {\n        return;\n      }\n      const shadow = makeShadow(shadowStyle);\n      if (shadowStyle.shadowInner) {\n        (json.innerShadows || []).push(shadow as FileFormat.InnerShadow);\n      } else {\n        (json.shadows || []).push(shadow as FileFormat.Shadow);\n      }\n    });\n  }\n\n  return json;\n};\n\nexport function parseStyle(json: FileFormat.Style): ViewStyle {\n  const style: ViewStyle = {};\n\n  if (json.contextSettings && json.contextSettings.opacity !== 1) {\n    style.opacity = json.contextSettings.opacity;\n  }\n\n  if (\n    json.fills &&\n    json.fills.length > 0 &&\n    json.fills[0].fillType === FileFormat.FillType.Color &&\n    json.fills[0].isEnabled\n  ) {\n    const color = json.fills[0].color;\n    style.backgroundColor = `#${Math.round(color.red * 255).toString(16)}${Math.round(\n      color.green * 255,\n    ).toString(16)}${Math.round(color.blue * 255).toString(16)}`;\n\n    if (color.alpha !== 1) {\n      style.backgroundColor += `${Math.round(color.alpha * 255).toString(16)}`;\n    }\n  }\n\n  if (\n    (json.shadows && json.shadows.length > 0 && json.shadows[0].isEnabled) ||\n    (json.innerShadows && json.innerShadows.length > 0 && json.innerShadows[0].isEnabled)\n  ) {\n    const isNormalShadow = json.shadows && json.shadows.length > 0 && json.shadows[0].isEnabled;\n    const shadow = isNormalShadow ? (json.shadows || [])[0] : (json.innerShadows || [])[0];\n    style.shadowRadius = shadow.blurRadius;\n    style.shadowSpread = shadow.spread;\n    style.shadowOffset = {\n      width: shadow.offsetX,\n      height: shadow.offsetY,\n    };\n\n    const color = shadow.color;\n    style.shadowColor = `#${Math.round(color.red * 255).toString(16)}${Math.round(\n      color.green * 255,\n    ).toString(16)}${Math.round(color.blue * 255).toString(16)}`;\n\n    if (color.alpha !== 1) {\n      style.shadowOpacity = color.alpha;\n    }\n\n    if (!isNormalShadow) {\n      style.shadowInner = true;\n    }\n  }\n\n  return style;\n}\n"
  },
  {
    "path": "src/jsonUtils/textLayers.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport { makeResizeConstraint } from './resizeConstraint';\nimport { TextNode, ResizeConstraints, TextStyle, ViewStyle, PlatformBridge } from '../types';\nimport { generateID, makeColorFromCSS } from './models';\nimport { makeStyle, parseStyle } from './style';\n\nexport const TEXT_DECORATION_UNDERLINE: { [key: string]: number } = {\n  none: FileFormat.UnderlineStyle.None,\n  underline: FileFormat.UnderlineStyle.Underlined,\n  double: 9,\n  'line-through': 0,\n};\n\nexport const TEXT_ALIGN: { [key: string]: number } = {\n  auto: FileFormat.TextHorizontalAlignment.Left,\n  left: FileFormat.TextHorizontalAlignment.Left,\n  right: FileFormat.TextHorizontalAlignment.Right,\n  center: FileFormat.TextHorizontalAlignment.Centered,\n  justify: FileFormat.TextHorizontalAlignment.Justified,\n};\n\nconst TEXT_ALIGN_REVERSE: { [key: number]: 'center' | 'auto' | 'left' | 'right' | 'justify' } = {\n  [FileFormat.TextHorizontalAlignment.Natural]: 'left',\n  [FileFormat.TextHorizontalAlignment.Right]: 'right',\n  [FileFormat.TextHorizontalAlignment.Centered]: 'center',\n  [FileFormat.TextHorizontalAlignment.Justified]: 'justify',\n} as const;\n\nexport const TEXT_DECORATION_LINETHROUGH: { [key: string]: number } = {\n  none: 0,\n  underline: 0,\n  double: 0,\n  'line-through': 1,\n};\n\nexport const TEXT_TRANSFORM: { [key: string]: number } = {\n  uppercase: FileFormat.TextTransform.Uppercase,\n  lowercase: FileFormat.TextTransform.Lowercase,\n  initial: FileFormat.TextTransform.None,\n  inherit: FileFormat.TextTransform.None,\n  none: FileFormat.TextTransform.None,\n  capitalize: FileFormat.TextTransform.None,\n};\n\n// this borrows heavily from react-native's RCTFont class\n// thanks y'all\n// https://github.com/facebook/react-native/blob/master/React/Views/RCTFont.mm\n\nexport const FONT_STYLES: { [key: string]: boolean } = {\n  normal: false,\n  italic: true,\n  oblique: true,\n};\n\nconst makeFontDescriptor = (bridge: PlatformBridge) => (\n  style: TextStyle,\n): FileFormat.FontDescriptor => ({\n  _class: 'fontDescriptor',\n  attributes: {\n    name: bridge.findFontName(style), // will default to the system font\n    size: style.fontSize || 14,\n  },\n});\n\nconst makeTextStyleAttributes = (bridge: PlatformBridge) => (style: TextStyle) =>\n  ({\n    underlineStyle: style.textDecoration ? TEXT_DECORATION_UNDERLINE[style.textDecoration] || 0 : 0,\n    strikethroughStyle: style.textDecoration\n      ? TEXT_DECORATION_LINETHROUGH[style.textDecoration] || 0\n      : 0,\n    paragraphStyle: {\n      _class: 'paragraphStyle',\n      alignment: TEXT_ALIGN[style.textAlign || 'auto'],\n      paragraphSpacing: style.paragraphSpacing || 0,\n      ...(typeof style.lineHeight !== 'undefined' && style.lineHeight !== null\n        ? {\n            minimumLineHeight: style.lineHeight,\n            maximumLineHeight: style.lineHeight,\n            lineHeightMultiple: 1.0,\n          }\n        : {}),\n    },\n    ...(typeof style.letterSpacing !== 'undefined' && style.letterSpacing !== null\n      ? {\n          kerning: style.letterSpacing,\n        }\n      : {}),\n    ...(typeof style.textTransform !== 'undefined' && style.textTransform !== null\n      ? {\n          MSAttributedStringTextTransformAttribute: TEXT_TRANSFORM[style.textTransform] * 1,\n        }\n      : {}),\n    MSAttributedStringFontAttribute: makeFontDescriptor(bridge)(style),\n    textStyleVerticalAlignmentKey: 0,\n    MSAttributedStringColorAttribute: makeColorFromCSS(style.color || 'black'),\n  } as const);\n\nconst makeAttribute = (bridge: PlatformBridge) => (\n  node: TextNode,\n  location: number,\n): FileFormat.StringAttribute => ({\n  _class: 'stringAttribute',\n  location,\n  length: node.content.length,\n  attributes: makeTextStyleAttributes(bridge)(node.textStyles),\n});\n\nconst makeAttributedString = (bridge: PlatformBridge) => (\n  textNodes: TextNode[],\n): FileFormat.AttributedString => {\n  const json: FileFormat.AttributedString = {\n    _class: 'attributedString',\n    string: '',\n    attributes: [],\n  };\n\n  let location = 0;\n\n  textNodes.forEach((node) => {\n    json.attributes.push(makeAttribute(bridge)(node, location));\n    json.string += node.content;\n    location += node.content.length;\n  });\n\n  return json;\n};\n\nexport const makeTextStyle = (bridge: PlatformBridge) => (\n  style: TextStyle,\n  shadows?: (ViewStyle | undefined | null)[] | null,\n): FileFormat.Style => {\n  const json = makeStyle(style, undefined, shadows);\n  json.textStyle = {\n    _class: 'textStyle',\n    encodedAttributes: makeTextStyleAttributes(bridge)(style),\n    verticalAlignment: FileFormat.TextVerticalAlignment.Top,\n  };\n  return json;\n};\n\nexport const parseTextStyle = (json: FileFormat.Style): TextStyle => {\n  const style: TextStyle = parseStyle(json);\n\n  if (json.textStyle) {\n    const attr = json.textStyle.encodedAttributes;\n    if (attr.underlineStyle) {\n      style.textDecoration = attr.underlineStyle === 9 ? 'double' : 'underline';\n    }\n\n    if (attr.strikethroughStyle) {\n      style.textDecoration = 'line-through';\n    }\n\n    if (\n      attr.paragraphStyle &&\n      attr.paragraphStyle.alignment &&\n      TEXT_ALIGN_REVERSE[attr.paragraphStyle.alignment]\n    ) {\n      style.textAlign = TEXT_ALIGN_REVERSE[attr.paragraphStyle.alignment];\n    }\n\n    if (attr.paragraphStyle && typeof attr.paragraphStyle.minimumLineHeight !== 'undefined') {\n      style.lineHeight = attr.paragraphStyle.minimumLineHeight;\n    }\n\n    if (typeof attr.kerning !== 'undefined') {\n      style.letterSpacing = attr.kerning;\n    }\n\n    const color = json.textStyle.encodedAttributes.MSAttributedStringColorAttribute;\n    if (color) {\n      style.color = `#${Math.round(color.red * 255).toString(16)}${Math.round(\n        color.green * 255,\n      ).toString(16)}${Math.round(color.blue * 255).toString(16)}`;\n\n      if (color.alpha !== 1) {\n        style.color += `${Math.round(color.alpha * 255).toString(16)}`;\n      }\n    }\n\n    if (\n      json.textStyle.encodedAttributes.MSAttributedStringTextTransformAttribute !==\n      FileFormat.TextTransform.None\n    ) {\n      style.textTransform =\n        json.textStyle.encodedAttributes.MSAttributedStringTextTransformAttribute ===\n        FileFormat.TextTransform.Lowercase\n          ? 'lowercase'\n          : 'uppercase';\n    }\n\n    const font = json.textStyle.encodedAttributes.MSAttributedStringFontAttribute;\n\n    style.fontSize = font.attributes.size;\n\n    // we are cheating here, setting the name of the font instead of parsing\n    // the family, weight and traits. react-sketchapp will handle it nevertheless\n    style.fontFamily = font.attributes.name;\n  }\n\n  return style;\n};\n\nexport const makeTextLayer = (bridge: PlatformBridge) => (\n  frame: FileFormat.Rect,\n  name: string,\n  textNodes: TextNode[],\n  _style: ViewStyle,\n  resizingConstraint?: ResizeConstraints | null,\n  shadows?: (ViewStyle | undefined | null)[] | null,\n): FileFormat.Text => ({\n  _class: 'text',\n  do_objectID: generateID(`text:${name}-${textNodes.map((node) => node.content).join('')}`),\n  frame,\n  isFlippedHorizontal: false,\n  isFlippedVertical: false,\n  isLocked: false,\n  isVisible: true,\n  layerListExpandedType: FileFormat.LayerListExpanded.Undecided,\n  name,\n  nameIsFixed: false,\n  resizingConstraint: makeResizeConstraint(resizingConstraint),\n  resizingType: FileFormat.ResizeType.Stretch,\n  rotation: 0,\n  shouldBreakMaskChain: false,\n  attributedString: makeAttributedString(bridge)(textNodes),\n  style: makeTextStyle(bridge)((textNodes[0] || { textStyles: {} }).textStyles, shadows),\n  automaticallyDrawOnUnderlyingPath: false,\n  dontSynchroniseWithSymbol: false,\n  // NOTE(akp): I haven't fully figured out the meaning of glyphBounds\n  glyphBounds: '',\n  // glyphBounds: '{{0, 0}, {116, 17}}',\n  lineSpacingBehaviour: FileFormat.LineSpacingBehaviour.ConsistentBaseline,\n  textBehaviour: FileFormat.TextBehaviour.Fixed,\n  booleanOperation: FileFormat.BooleanOperation.NA,\n  exportOptions: {\n    _class: 'exportOptions',\n    exportFormats: [],\n    includedLayerIds: [],\n    layerOptions: 0,\n    shouldTrim: false,\n  },\n  isFixedToViewport: false,\n});\n"
  },
  {
    "path": "src/platformBridges/macos.ts",
    "content": "import { PlatformBridge } from '../types';\n\nimport { createStringMeasurer, findFontName, makeImageDataFromUrl } from 'node-sketch-bridge';\n\nconst NodeMacOSBridge: PlatformBridge = {\n  createStringMeasurer,\n  findFontName,\n  makeImageDataFromUrl,\n};\n\nexport default NodeMacOSBridge;\n"
  },
  {
    "path": "src/platformBridges/sketch/createStringMeasurer.ts",
    "content": "import { Size, TextNode, TextStyle } from '../../types';\nimport {\n  TEXT_DECORATION_UNDERLINE,\n  TEXT_DECORATION_LINETHROUGH,\n  TEXT_ALIGN,\n  TEXT_TRANSFORM,\n} from '../../jsonUtils/textLayers';\nimport { makeColorFromCSS } from '../../jsonUtils/models';\nimport { findFont } from './findFontName';\n\n// TODO(lmr): do something more sensible here\nconst FLOAT_MAX = 999999;\n\nfunction makeParagraphStyle(textStyle: TextStyle) {\n  const pStyle = NSMutableParagraphStyle.alloc().init();\n  if (textStyle.lineHeight !== undefined) {\n    pStyle.minimumLineHeight = textStyle.lineHeight;\n    pStyle.lineHeightMultiple = 1.0;\n    pStyle.maximumLineHeight = textStyle.lineHeight;\n  }\n\n  if (textStyle.textAlign) {\n    pStyle.alignment = TEXT_ALIGN[textStyle.textAlign];\n  }\n\n  // TODO: check against only positive spacing values?\n  if (textStyle.paragraphSpacing !== undefined) {\n    pStyle.paragraphSpacing = textStyle.paragraphSpacing;\n  }\n\n  return pStyle;\n}\n\n// This shouldn't need to call into Sketch, but it does currently, which is bad for perf :(\nfunction createStringAttributes(textStyles: TextStyle): Object {\n  const font = findFont(textStyles);\n  const { textDecoration } = textStyles;\n\n  const underline = textDecoration && TEXT_DECORATION_UNDERLINE[textDecoration];\n  const strikethrough = textDecoration && TEXT_DECORATION_LINETHROUGH[textDecoration];\n\n  const attribs: any = {\n    MSAttributedStringFontAttribute: font.fontDescriptor(),\n    NSFont: font,\n    NSParagraphStyle: makeParagraphStyle(textStyles),\n    NSUnderline: underline || 0,\n    NSStrikethrough: strikethrough || 0,\n  };\n\n  const color = makeColorFromCSS(textStyles.color || 'black');\n  attribs.MSAttributedStringColorAttribute = color;\n\n  if (textStyles.letterSpacing !== undefined && textStyles.letterSpacing !== null) {\n    attribs.NSKern = textStyles.letterSpacing;\n  }\n\n  if (textStyles.textTransform !== undefined && textStyles.textTransform !== null) {\n    attribs.MSAttributedStringTextTransformAttribute = TEXT_TRANSFORM[textStyles.textTransform] * 1;\n  }\n\n  return attribs;\n}\n\ntype NSAttributedString = any;\n\nfunction createAttributedString(textNode: TextNode): NSAttributedString {\n  const { content, textStyles } = textNode;\n\n  const attribs = createStringAttributes(textStyles);\n\n  return NSAttributedString.attributedStringWithString_attributes_(content, attribs);\n}\n\nexport function createStringMeasurer(textNodes: TextNode[], width: number): Size {\n  const fullStr = NSMutableAttributedString.alloc().init();\n  textNodes.forEach((textNode) => {\n    const newString = createAttributedString(textNode);\n    fullStr.appendAttributedString(newString);\n  });\n  const {\n    height: measureHeight,\n    width: measureWidth,\n  } = fullStr.boundingRectWithSize_options_context(\n    CGSizeMake(width, FLOAT_MAX),\n    NSStringDrawingUsesLineFragmentOrigin,\n    null,\n  ).size;\n  return { width: measureWidth, height: measureHeight };\n}\n"
  },
  {
    "path": "src/platformBridges/sketch/findFontName.ts",
    "content": "import { hashStyle } from '../../utils/hashStyle';\nimport { TextStyle } from '../../types';\nimport { FONT_STYLES } from '../../jsonUtils/textLayers';\n\n// this borrows heavily from react-native's RCTFont class\n// thanks y'all\n// https://github.com/facebook/react-native/blob/master/React/Views/RCTFont.mm\n\nconst FONT_WEIGHTS: { [key: string]: number } = {\n  ultralight: -0.8,\n  '100': -0.8,\n  thin: -0.6,\n  '200': -0.6,\n  light: -0.4,\n  '300': -0.4,\n  normal: 0,\n  regular: 0,\n  '400': 0,\n  semibold: 0.23,\n  demibold: 0.23,\n  '500': 0.23,\n  '600': 0.3,\n  bold: 0.4,\n  '700': 0.4,\n  extrabold: 0.56,\n  ultrabold: 0.56,\n  heavy: 0.56,\n  '800': 0.56,\n  black: 0.62,\n  '900': 0.62,\n};\n\ntype NSFont = any;\n\nconst isItalicFont = (font: NSFont): boolean => {\n  const traits = font.fontDescriptor().objectForKey(NSFontTraitsAttribute);\n  const symbolicTraits = traits[NSFontSymbolicTrait].unsignedIntValue();\n\n  return (symbolicTraits & NSFontItalicTrait) !== 0;\n};\n\nconst isCondensedFont = (font: NSFont): boolean => {\n  const traits = font.fontDescriptor().objectForKey(NSFontTraitsAttribute);\n  const symbolicTraits = traits[NSFontSymbolicTrait].unsignedIntValue();\n\n  return (symbolicTraits & NSFontCondensedTrait) !== 0;\n};\n\nconst weightOfFont = (font: NSFont): number => {\n  const traits = font.fontDescriptor().objectForKey(NSFontTraitsAttribute);\n\n  const weight = traits[NSFontWeightTrait].doubleValue();\n  if (weight === 0.0) {\n    const weights = Object.keys(FONT_WEIGHTS);\n    const fontName = String(font.fontName()).toLowerCase();\n    const matchingWeight = weights.find((w) => fontName.endsWith(w));\n    if (matchingWeight) {\n      return FONT_WEIGHTS[matchingWeight];\n    }\n  }\n\n  return weight;\n};\n\nconst fontNamesForFamilyName = (familyName: string): Array<string> => {\n  const manager = NSFontManager.sharedFontManager();\n  const members = NSArray.arrayWithArray(manager.availableMembersOfFontFamily(familyName));\n\n  const results = [];\n  for (let i = 0; i < members.length; i += 1) {\n    results.push(members[i][0]);\n  }\n\n  return results;\n};\n\nconst useCache = true;\nconst _cache: Map<string, NSFont> = new Map();\n\nconst getCached = (key: string): NSFont => {\n  if (!useCache) return undefined;\n  return _cache.get(key);\n};\n\nexport const findFont = (style: TextStyle): NSFont => {\n  const cacheKey = hashStyle(style);\n\n  let font = getCached(cacheKey);\n  if (font) {\n    return font;\n  }\n  const defaultFontFamily = NSFont.systemFontOfSize(14).familyName();\n  const defaultFontWeight = NSFontWeightRegular;\n  const defaultFontSize = 14;\n\n  const fontSize = style.fontSize ? style.fontSize : defaultFontSize;\n  let fontWeight = FONT_WEIGHTS[String(style.fontWeight).toLowerCase()] || defaultFontWeight;\n\n  let familyName = defaultFontFamily;\n  let isItalic = false;\n  let isCondensed = false;\n\n  if (style.fontFamily) {\n    familyName = style.fontFamily;\n  }\n\n  if (style.fontStyle) {\n    isItalic = FONT_STYLES[style.fontStyle] || false;\n  }\n\n  let didFindFont = false;\n\n  // Handle system font as special case. This ensures that we preserve\n  // the specific metrics of the standard system font as closely as possible.\n  if (familyName === defaultFontFamily || familyName === 'System') {\n    font = NSFont.systemFontOfSize_weight(fontSize, fontWeight);\n\n    if (font) {\n      didFindFont = true;\n\n      if (isItalic || isCondensed) {\n        let fontDescriptor = font.fontDescriptor();\n        let symbolicTraits = fontDescriptor.symbolicTraits();\n        if (isItalic) {\n          symbolicTraits |= NSFontItalicTrait;\n        }\n\n        if (isCondensed) {\n          symbolicTraits |= NSFontCondensedTrait;\n        }\n\n        fontDescriptor = fontDescriptor.fontDescriptorWithSymbolicTraits(symbolicTraits);\n        font = NSFont.fontWithDescriptor_size(fontDescriptor, fontSize);\n      }\n    }\n  }\n\n  const fontNames = fontNamesForFamilyName(familyName);\n\n  // Gracefully handle being given a font name rather than font family, for\n  // example: \"Helvetica Light Oblique\" rather than just \"Helvetica\".\n  if (!didFindFont && fontNames.length === 0) {\n    font = NSFont.fontWithName_size(familyName, fontSize);\n    if (font) {\n      // It's actually a font name, not a font family name,\n      // but we'll do what was meant, not what was said.\n      familyName = font.familyName();\n      fontWeight = style.fontWeight ? fontWeight : weightOfFont(font);\n      isItalic = style.fontStyle ? isItalic : isItalicFont(font);\n      isCondensed = isCondensedFont(font);\n    } else {\n      font = NSFont.systemFontOfSize_weight(fontSize, fontWeight);\n    }\n\n    didFindFont = true;\n  }\n\n  if (!didFindFont) {\n    // Get the closest font that matches the given weight for the fontFamily\n    let closestWeight = Infinity;\n    for (let i = 0; i < fontNames.length; i += 1) {\n      const match = NSFont.fontWithName_size(fontNames[i], fontSize);\n\n      if (isItalic === isItalicFont(match) && isCondensed === isCondensedFont(match)) {\n        const testWeight = weightOfFont(match);\n\n        if (Math.abs(testWeight - fontWeight) < Math.abs(closestWeight - fontWeight)) {\n          font = match;\n\n          closestWeight = testWeight;\n        }\n      }\n    }\n  }\n\n  // If we still don't have a match at least return the first font in the fontFamily\n  // This is to support built-in font Zapfino and other custom single font families like Impact\n  if (!font) {\n    if (fontNames.length > 0) {\n      font = NSFont.fontWithName_size(fontNames[0], fontSize);\n    }\n  }\n\n  // TODO(gold): support opentype features: small-caps & number types\n\n  if (font) {\n    _cache.set(cacheKey, font);\n  }\n\n  return font;\n};\n\nexport function findFontName(style: TextStyle): string {\n  const font = findFont(style);\n  return String(font.fontDescriptor().postscriptName());\n}\n"
  },
  {
    "path": "src/platformBridges/sketch/index.ts",
    "content": "import { PlatformBridge } from '../../types';\nimport { createStringMeasurer } from './createStringMeasurer';\nimport { findFontName } from './findFontName';\nimport { makeImageDataFromUrl } from './makeImageDataFromUrl';\n\nconst SketchBridge: PlatformBridge = {\n  createStringMeasurer,\n  findFontName,\n  makeImageDataFromUrl,\n};\n\nexport default SketchBridge;\n"
  },
  {
    "path": "src/platformBridges/sketch/makeImageDataFromUrl.ts",
    "content": "export function makeImageDataFromUrl(url?: string) {\n  let fetchedData = url ? NSData.dataWithContentsOfURL(NSURL.URLWithString(url)) : undefined;\n\n  if (fetchedData) {\n    const firstByte = String(\n      NSString.alloc().initWithData_encoding(fetchedData, NSISOLatin1StringEncoding),\n    ).charCodeAt(0);\n\n    // Check for first byte to see if we have an image.\n    // 0xFF = JPEG, 0x89 = PNG, 0x47 = GIF, 0x49 = TIFF, 0x4D = TIFF\n    if (\n      firstByte !== 0xff &&\n      firstByte !== 0x89 &&\n      firstByte !== 0x47 &&\n      firstByte !== 0x49 &&\n      firstByte !== 0x4d\n    ) {\n      fetchedData = null;\n    }\n  }\n\n  let image: any;\n\n  if (!fetchedData) {\n    const errorUrl =\n      'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mM8w8DwHwAEOQHNmnaaOAAAAABJRU5ErkJggg==';\n    image = NSImage.alloc().initWithContentsOfURL(NSURL.URLWithString(errorUrl));\n  } else {\n    image = NSImage.alloc().initWithData(fetchedData);\n  }\n\n  let imageData: any;\n\n  if (MSImageData.alloc().initWithImage_convertColorSpace !== undefined) {\n    imageData = MSImageData.alloc().initWithImage_convertColorSpace(image, false);\n  } else {\n    imageData = MSImageData.alloc().initWithImage(image);\n  }\n\n  return String(\n    imageData.data().base64EncodedStringWithOptions(NSDataBase64EncodingEndLineWithCarriageReturn),\n  );\n}\n"
  },
  {
    "path": "src/render.tsx",
    "content": "import * as React from 'react';\nimport { fromSJSON } from './jsonUtils/sketchJson/fromSJSON';\nimport { buildTree } from './buildTree';\nimport { flexToSketchJSON } from './flexToSketchJSON';\nimport { resetLayer, resetDocument } from './resets';\nimport { injectSymbols } from './symbol';\nimport {\n  SketchDocumentData,\n  SketchLayer,\n  SketchPage,\n  TreeNode,\n  WrappedSketchLayer,\n  PlatformBridge,\n} from './types';\nimport { RedBox } from './components/RedBox';\nimport {\n  getDocumentDataFromContainer,\n  getDocumentDataFromContext,\n  getDocumentData,\n} from './utils/getDocument';\nimport { isNativeDocument } from './utils/isNativeDocument';\nimport { isNativePage } from './utils/isNativePage';\nimport { isNativeSymbolsPage } from './utils/isNativeSymbolsPage';\n\nexport const renderLayers = (layers: Array<any>, container: SketchLayer): SketchLayer => {\n  if (container.addLayers === undefined) {\n    throw new Error(\n      ` React SketchApp cannot render into this layer. You may be trying to render into a layer that does not take children. Try rendering into a LayerGroup, Artboard, or Page.`,\n    );\n  }\n\n  container.addLayers(layers);\n  return container;\n};\n\nconst getDefaultPage = (): SketchLayer => {\n  const doc = getDocumentDataFromContext(context);\n  const currentPage = doc.currentPage();\n\n  return isNativeSymbolsPage(currentPage) ? doc.addBlankPage() : currentPage;\n};\n\nconst renderContents = (bridge: PlatformBridge) => (\n  tree: TreeNode | string,\n  container: SketchLayer,\n): SketchLayer => {\n  const json = flexToSketchJSON(bridge)(tree);\n  const layer = fromSJSON(json, '119');\n\n  return renderLayers([layer], container);\n};\n\nconst renderPage = (bridge: PlatformBridge) => (\n  tree: TreeNode,\n  page: SketchPage,\n): Array<SketchLayer> => {\n  const children = tree.children || [];\n\n  // assume if name is set on this nested page, the intent is to overwrite\n  // the name of the page it is getting rendered into\n  if (tree.props.name) {\n    page.setName(tree.props.name);\n  }\n\n  return children.map((child) => renderContents(bridge)(child, page));\n};\n\nconst renderDocument = (bridge: PlatformBridge) => (\n  tree: TreeNode,\n  documentData: SketchDocumentData,\n): Array<SketchLayer> => {\n  const initialPage = documentData.currentPage();\n  const shouldRenderInitialPage = !isNativeSymbolsPage(initialPage);\n  const children = tree.children || [];\n\n  return children.map((child, i) => {\n    if (typeof child === 'string' || child.type !== 'sketch_page') {\n      throw new Error('Document children must be of type Page');\n    }\n\n    const page = i === 0 && shouldRenderInitialPage ? initialPage : documentData.addBlankPage();\n    return renderPage(bridge)(child, page);\n  });\n};\n\nconst renderTree = (bridge: PlatformBridge) => (\n  tree: TreeNode,\n  _container?: SketchLayer,\n): SketchLayer | Array<SketchLayer> => {\n  if (tree.type === 'sketch_document') {\n    if (_container && !isNativeDocument(_container)) {\n      throw new Error('Cannot render a Document into a child of Document');\n    }\n\n    const doc = getDocumentData(_container);\n\n    if (!doc) {\n      return;\n    }\n\n    resetDocument(doc);\n    return renderDocument(bridge)(tree, doc);\n  }\n\n  if (isNativeDocument(_container)) {\n    throw new Error('You need to render a Document into Document');\n  }\n\n  if (tree.type === 'sketch_page') {\n    if (_container && !isNativePage(_container)) {\n      throw new Error('You need to render a Page into Page');\n    }\n  }\n\n  const container = _container || getDefaultPage();\n\n  resetLayer(container);\n  return tree.type === 'sketch_page'\n    ? renderPage(bridge)(tree, container)\n    : renderContents(bridge)(tree, container);\n};\n\nexport const render = (bridge: PlatformBridge) => (\n  element: React.ReactElement,\n  container?: SketchLayer | WrappedSketchLayer,\n): SketchLayer | Array<SketchLayer> => {\n  let nativeContainer: SketchLayer | undefined;\n  if (container && container.sketchObject) {\n    nativeContainer = container.sketchObject;\n  } else if (container) {\n    nativeContainer = container;\n  }\n\n  // The Symbols page holds a special meaning within Sketch / react-sketchapp\n  // and due to how `makeSymbol` works, we cannot render into it\n  if (isNativeSymbolsPage(nativeContainer)) {\n    throw Error('Cannot render into Symbols page');\n  }\n\n  try {\n    const tree = buildTree(bridge)(element);\n\n    injectSymbols(getDocumentDataFromContainer(nativeContainer));\n\n    return renderTree(bridge)(tree, nativeContainer);\n  } catch (err) {\n    console.error(err);\n    const tree = buildTree(bridge)(<RedBox error={err} />);\n    return renderContents(bridge)(tree, nativeContainer);\n  }\n};\n"
  },
  {
    "path": "src/renderToJSON.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport { PlatformBridge } from './types';\nimport { buildTree } from './buildTree';\nimport { flexToSketchJSON } from './flexToSketchJSON';\nimport * as React from 'react';\n\nexport const renderToJSON = (platformBridge: PlatformBridge) => (\n  element: React.ReactElement,\n): FileFormat.AnyLayer => {\n  const tree = buildTree(platformBridge)(element);\n  return flexToSketchJSON(platformBridge)(tree);\n};\n"
  },
  {
    "path": "src/renderers/ArtboardRenderer.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport { generateID, makeRect, makeColorFromCSS } from '../jsonUtils/models';\nimport { makeResizeConstraint } from '../jsonUtils/resizeConstraint';\nimport { SketchRenderer } from './SketchRenderer';\nimport { TreeNode } from '../types';\nimport { Props } from '../components/Artboard';\n\nexport class ArtboardRenderer extends SketchRenderer {\n  renderGroupLayer({ layout, style, props }: TreeNode<Props>): FileFormat.Artboard {\n    let color: FileFormat.Color | undefined;\n    if (style.backgroundColor !== undefined) {\n      color = makeColorFromCSS(style.backgroundColor);\n    }\n\n    return {\n      _class: 'artboard',\n      do_objectID: generateID(`artboard:${props.name}`, !!props.name),\n      frame: makeRect(layout.left, layout.top, layout.width, layout.height),\n      name: props.name || 'Artboard',\n      nameIsFixed: props.name !== undefined,\n      isVisible: true,\n      backgroundColor: color || makeColorFromCSS('white'),\n      hasBackgroundColor: color !== undefined,\n      isFlowHome: !!props.isHome,\n      ...(props.viewport && {\n        presetDictionary: {\n          allowResizedMatching: 0,\n          offersLandscapeVariant: 1,\n\n          name: props.viewport.name,\n          width: props.viewport.width,\n          height: props.viewport.height,\n        },\n      }),\n      isFlippedHorizontal: false,\n      isFlippedVertical: false,\n      isFixedToViewport: false,\n      isLocked: false,\n      booleanOperation: FileFormat.BooleanOperation.NA,\n      exportOptions: {\n        _class: 'exportOptions',\n        exportFormats: [],\n        includedLayerIds: [],\n        layerOptions: 0,\n        shouldTrim: false,\n      },\n      layerListExpandedType: FileFormat.LayerListExpanded.Undecided,\n      resizingType: FileFormat.ResizeType.Stretch,\n      shouldBreakMaskChain: false,\n      hasClickThrough: false,\n      layers: [],\n      includeInCloudUpload: true,\n      includeBackgroundColorInExport: color !== undefined,\n      horizontalRulerData: {\n        _class: 'rulerData',\n        base: 0,\n        guides: [],\n      },\n      verticalRulerData: {\n        _class: 'rulerData',\n        base: 0,\n        guides: [],\n      },\n      resizingConstraint: makeResizeConstraint(),\n      resizesContent: false,\n      rotation: 0,\n    };\n  }\n}\n"
  },
  {
    "path": "src/renderers/ImageRenderer.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport { SketchRenderer } from './SketchRenderer';\nimport { getImageDataFromURL } from '../utils/getImageDataFromURL';\n// import processTransform from './processTransform';\nimport { makeRect, makeImageFill, makeJSONDataReference, generateID } from '../jsonUtils/models';\nimport { makeRectShapeLayer, makeShapeGroup } from '../jsonUtils/shapeLayers';\nimport { createBorders } from '../jsonUtils/borders';\nimport { TreeNode } from '../types';\nimport { Props } from '../components/Image';\n\nfunction extractURLFromSource(source?: string | { uri?: string } | null): string | undefined {\n  if (typeof source === 'string') {\n    return source;\n  }\n  return (source || {}).uri;\n}\n\nexport class ImageRenderer extends SketchRenderer {\n  renderBackingLayers({\n    layout,\n    style,\n    props,\n  }: TreeNode<Props & { resizeMode?: FileFormat.PatternFillType }>) {\n    let layers: FileFormat.ShapeGroup[] = [];\n\n    const {\n      borderTopLeftRadius = 0,\n      borderTopRightRadius = 0,\n      borderBottomRightRadius = 0,\n      borderBottomLeftRadius = 0,\n    } = style;\n\n    const url = extractURLFromSource(props.source);\n\n    const image = getImageDataFromURL(this.platformBridge)(url);\n\n    const fillImage = makeJSONDataReference(image);\n\n    const frame = makeRect(0, 0, layout.width, layout.height);\n    const radii = [\n      borderTopLeftRadius,\n      borderTopRightRadius,\n      borderBottomRightRadius,\n      borderBottomLeftRadius,\n    ];\n    const shapeLayer = makeRectShapeLayer(0, 0, layout.width, layout.height, radii);\n\n    const fills = [makeImageFill(fillImage, props.resizeMode)];\n\n    const content = makeShapeGroup(frame, [shapeLayer], style, props.shadows, fills);\n\n    // try to keep a constant ID based on the URL\n    content.do_objectID = generateID(url);\n\n    const contents = createBorders(content, layout, style);\n\n    layers = layers.concat(contents);\n\n    return layers;\n  }\n}\n"
  },
  {
    "path": "src/renderers/SketchRenderer.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport { layerGroup } from '../jsonUtils/layerGroup';\nimport { hotspotLayer } from '../jsonUtils/hotspotLayer';\nimport { TreeNode, PlatformBridge } from '../types';\nimport { processTransform } from '../utils/processTransform';\n\nconst DEFAULT_OPACITY = 1.0;\n\nexport class SketchRenderer {\n  protected readonly platformBridge: PlatformBridge;\n\n  constructor(bridge: PlatformBridge) {\n    this.platformBridge = bridge;\n  }\n\n  getDefaultGroupName(_props: any) {\n    return 'Group';\n  }\n\n  renderGroupLayer({\n    layout,\n    style,\n    props,\n  }: TreeNode):\n    | FileFormat.SymbolMaster\n    | FileFormat.Artboard\n    | FileFormat.Group\n    | FileFormat.ShapeGroup\n    | FileFormat.SymbolInstance {\n    // Default SketchRenderer just renders an empty group\n\n    const transform = processTransform(layout, style);\n\n    const opacity =\n      style.opacity !== undefined && style.opacity !== null ? style.opacity : DEFAULT_OPACITY;\n\n    return {\n      ...layerGroup(\n        layout.left,\n        layout.top,\n        layout.width,\n        layout.height,\n        opacity,\n        props.resizingConstraint,\n      ),\n      name: props.name || this.getDefaultGroupName(props),\n      ...transform,\n      ...(props.flow && hotspotLayer(props.flow)),\n    };\n  }\n\n  renderBackingLayers(\n    _node: TreeNode,\n  ): (\n    | FileFormat.ShapePath\n    | FileFormat.Rectangle\n    | FileFormat.SymbolMaster\n    | FileFormat.Group\n    | FileFormat.Polygon\n    | FileFormat.Star\n    | FileFormat.Triangle\n    | FileFormat.ShapeGroup\n    | FileFormat.Text\n    | FileFormat.SymbolInstance\n    | FileFormat.Slice\n    | FileFormat.Hotspot\n    | FileFormat.Bitmap\n  )[] {\n    return [];\n  }\n}\n"
  },
  {
    "path": "src/renderers/SvgRenderer.ts",
    "content": "import { ViewRenderer } from './ViewRenderer';\nimport { TreeNode } from '../types';\nimport { makeSvgLayer } from '../jsonUtils/makeSvgLayer';\nimport { Props } from '../components/Svg/Svg';\n\nconst snakeExceptions = [\n  'gradientUnits',\n  'gradientTransform',\n  'patternUnits',\n  'patternTransform',\n  'stdDeviation',\n  'numOctaves',\n  'specularExponent',\n  'specularConstant',\n  'surfaceScale',\n  'viewBox',\n];\nfunction toSnakeCase(string: string) {\n  if (string === 'href') {\n    return 'xlink:href';\n  }\n  if (snakeExceptions.indexOf(string) !== -1) {\n    return string;\n  }\n  return string.replace(/([A-Z])/g, ($1) => `-${$1.toLowerCase()}`);\n}\n\nfunction makeSvgString(el: string | TreeNode<Props>) {\n  if (typeof el === 'string') {\n    return el;\n  }\n  const { type, props, children } = el;\n\n  if (props && props.textNodes && props.textNodes.length) {\n    return props.textNodes.reduce((prev, textNode) => prev + textNode.content, '');\n  }\n\n  if (!type || type.indexOf('svg_') !== 0) {\n    throw new Error(\n      `Could not render type '${type}'. Make sure to only have <Svg.*> components inside <Svg>.`,\n    );\n  }\n\n  const cleanedType = type.slice(4);\n  const attributes = Object.keys(props || {}).reduce(\n    // @ts-ignore\n    (prev, k) => (props[k] ? `${prev} ${toSnakeCase(k)}=\"${props[k]}\"` : prev),\n    '',\n  );\n\n  let string = `<${cleanedType}${attributes}`;\n\n  if (!children || !children.length) {\n    string += '/>\\n';\n  } else {\n    string += '>\\n';\n    string += (children || []).reduce((prev, c) => `${prev}  ${makeSvgString(c)}`, '');\n    string += `</${cleanedType}>\\n`;\n  }\n\n  return string;\n}\n\nexport class SvgRenderer extends ViewRenderer {\n  getDefaultGroupName(props: Props) {\n    return props.name || 'Svg';\n  }\n\n  renderBackingLayers(node: TreeNode<Props>) {\n    const layers = super.renderBackingLayers(node);\n\n    const { layout, props, children, style } = node;\n\n    // add the \"xmlns:xlink\" namespace so we can use `href`\n    props['xmlns:xlink'] = 'http://www.w3.org/1999/xlink';\n\n    const svgString = makeSvgString({\n      type: 'svg_svg',\n      props,\n      children,\n      style,\n      layout,\n    });\n\n    const svgLayer = makeSvgLayer(layout, 'Shape', svgString);\n\n    layers.push(svgLayer);\n\n    return layers;\n  }\n}\n"
  },
  {
    "path": "src/renderers/SymbolInstanceRenderer.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport { SketchRenderer } from './SketchRenderer';\nimport {\n  makeSymbolInstance,\n  makeRect,\n  makeJSONDataReference,\n  makeOverride,\n} from '../jsonUtils/models';\nimport { TreeNode } from '../types';\nimport { getSymbolMasterById, SymbolInstanceProps } from '../symbol';\nimport { getImageDataFromURL } from '../utils/getImageDataFromURL';\n\ntype Override = {\n  type: 'symbolID' | 'stringValue' | 'layerStyle' | 'textStyle' | 'flowDestination' | 'image';\n  path: string;\n  name: string;\n  symbolID?: string;\n};\n\nconst findInGroup = (layer: FileFormat.AnyGroup, type: string): FileFormat.AnyLayer | undefined =>\n  layer && layer.layers && layer.layers.find((l) => l._class === type);\n\nconst hasImageFill = (layer: FileFormat.AnyLayer): boolean =>\n  !!(layer.style && layer.style.fills && layer.style.fills.some((f) => f.image));\n\nconst removeDuplicateOverrides = (overrides: Array<Override>): Array<Override> => {\n  const seen: { [path: string]: boolean } = {};\n\n  return overrides.filter(({ path }) => {\n    const isDuplicate = typeof seen[path] !== 'undefined';\n    seen[path] = true;\n\n    return !isDuplicate;\n  });\n};\n\nconst extractOverridesReducer = (path: string) => (\n  overrides: Override[],\n  layer: FileFormat.AnyLayer,\n): Override[] => {\n  if (layer._class === 'text') {\n    return overrides.concat({\n      type: 'stringValue',\n      path: `${path}${layer.do_objectID}`,\n      name: layer.name,\n    });\n  }\n\n  if (layer._class === 'group') {\n    // here we're doing some look-ahead to see if this group contains a group\n    // that contains text. this is the structure that will appear if the user\n    // creates a `<Text />` element with a custom name\n    const subGroup = findInGroup(layer, 'group') as FileFormat.Group;\n    const textLayer = findInGroup(subGroup, 'text') as FileFormat.Text;\n    if (textLayer) {\n      return overrides.concat({\n        type: 'stringValue',\n        path: `${path}${textLayer.do_objectID}`,\n        name: textLayer.name,\n      });\n    }\n\n    // here we're doing look-ahead to see if this group contains a shapeGroup\n    // with an image fill. if it does we can do an image override on that\n    // fill\n    const shapeGroup = findInGroup(layer, 'shapeGroup');\n    if (shapeGroup && hasImageFill(shapeGroup)) {\n      return overrides.concat({\n        type: 'image',\n        path: `${path}${shapeGroup.do_objectID}`,\n        name: layer.name,\n      });\n    }\n  }\n\n  if (layer._class === 'symbolInstance') {\n    return overrides.concat({\n      type: 'symbolID',\n      path: `${path}${layer.do_objectID}`,\n      name: layer.name,\n      symbolID: layer.symbolID,\n    });\n  }\n\n  if (\n    (layer._class === 'shapeGroup' || layer._class === 'artboard' || layer._class === 'group') &&\n    layer.layers\n  ) {\n    return layer.layers.reduce(extractOverridesReducer(path), overrides);\n  }\n\n  return overrides;\n};\n\nconst extractOverrides = (layers: FileFormat.AnyLayer[] = [], path?: string): Override[] => {\n  const overrides = layers.reduce(extractOverridesReducer(path || ''), []);\n  return removeDuplicateOverrides(overrides);\n};\n\nexport class SymbolInstanceRenderer extends SketchRenderer {\n  renderGroupLayer({\n    layout,\n    props,\n  }: TreeNode<SymbolInstanceProps & { symbolID: string; name: string }>) {\n    const bridge = this.platformBridge;\n    const masterTree = getSymbolMasterById(props.symbolID);\n\n    if (!masterTree) {\n      throw new Error(\n        'Trying to create a symbol instance for a Symbol Master that does not exists',\n      );\n    }\n\n    const symbolInstance = makeSymbolInstance(\n      makeRect(layout.left, layout.top, layout.width, layout.height),\n      masterTree.symbolID,\n      props.name,\n      props.resizingConstraint,\n    );\n\n    const { overrides } = props;\n\n    if (!overrides) {\n      return symbolInstance;\n    }\n\n    const overridableLayers = extractOverrides(masterTree.layers);\n\n    const overrideValues = overridableLayers.reduce(function inject(\n      memo: FileFormat.OverrideValue[],\n      reference: Override,\n    ) {\n      if (reference.type === 'symbolID') {\n        const newPath = `${reference.path}/`;\n        const originalMaster = getSymbolMasterById(reference.symbolID);\n\n        if (!originalMaster) {\n          return memo;\n        }\n\n        if (reference.name in overrides) {\n          const overrideValue = overrides[reference.name];\n          // @ts-ignore\n          const overrideSymbolId = overrideValue.symbolID;\n          if (typeof overrideValue !== 'function' || typeof overrideSymbolId !== 'string') {\n            throw new Error(\n              `The overriden nested symbol needs to be the constructor of another symbol.\\n\\nIn Symbol Instance: \"${props.name}\"\\nFor Override: \"${reference.name}\"`,\n            );\n          }\n\n          const replacementMaster = getSymbolMasterById(overrideSymbolId);\n\n          if (!replacementMaster) {\n            return memo;\n          }\n\n          if (\n            originalMaster.frame.width !== replacementMaster.frame.width ||\n            originalMaster.frame.height !== replacementMaster.frame.height\n          ) {\n            throw new Error(\n              `The overriden nested symbol needs to have the same dimensions.\\n\\nIn Symbol Instance: \"${props.name}\"\\nFor Override: \"${reference.name}\"`,\n            );\n          }\n\n          memo.push(makeOverride(reference.path, reference.type, replacementMaster.symbolID));\n\n          extractOverrides(replacementMaster.layers, newPath).reduce(inject, memo);\n\n          return memo;\n        }\n\n        extractOverrides(originalMaster.layers, newPath).reduce(inject, memo);\n\n        return memo;\n      }\n\n      if (!overrides.hasOwnProperty(reference.name)) {\n        return memo;\n      }\n\n      const overrideValue = overrides[reference.name];\n\n      if (reference.type === 'stringValue') {\n        if (typeof overrideValue !== 'string') {\n          throw new Error(\n            `The override value of a Text must be a string.\\n\\nIn Symbol Instance: \"${props.name}\"\\nFor Override: \"${reference.name}\"`,\n          );\n        }\n        memo.push(makeOverride(reference.path, reference.type, overrideValue));\n      }\n\n      if (reference.type === 'image') {\n        if (typeof overrideValue !== 'string') {\n          throw new Error(\n            `The override value of an Image must be a url.\\n\\nIn Symbol Instance: \"${props.name}\"\\nFor Override: \"${reference.name}\"`,\n          );\n        }\n        memo.push(\n          makeOverride(\n            reference.path,\n            reference.type,\n            makeJSONDataReference(getImageDataFromURL(bridge)(overrideValue)),\n          ),\n        );\n      }\n\n      return memo;\n    },\n    []);\n\n    symbolInstance.overrideValues = overrideValues;\n\n    return symbolInstance;\n  }\n}\n"
  },
  {
    "path": "src/renderers/SymbolMasterRenderer.ts",
    "content": "import { makeSymbolMaster, makeRect } from '../jsonUtils/models';\nimport { SketchRenderer } from './SketchRenderer';\nimport { TreeNode } from '../types';\nimport { SymbolMasterProps } from '../symbol';\n\nexport class SymbolMasterRenderer extends SketchRenderer {\n  renderGroupLayer({\n    layout,\n    props,\n  }: TreeNode<SymbolMasterProps & { symbolID: string; name: string }>) {\n    return makeSymbolMaster(\n      makeRect(layout.left, layout.top, layout.width, layout.height),\n      props.symbolID,\n      props.name,\n    );\n  }\n}\n"
  },
  {
    "path": "src/renderers/TextRenderer.ts",
    "content": "import { SketchRenderer } from './SketchRenderer';\nimport { TreeNode } from '../types';\nimport { makeTextLayer } from '../jsonUtils/textLayers';\nimport { makeRect } from '../jsonUtils/models';\nimport { TextStyles } from '../sharedStyles/TextStyles';\nimport { Props } from '../components/Text';\n\nexport class TextRenderer extends SketchRenderer {\n  getDefaultGroupName(props: Props) {\n    return props.name || 'Text';\n  }\n\n  renderBackingLayers({ layout, style, textStyle, props }: TreeNode<Props>) {\n    // Append all text nodes's content into one string if name is missing\n    const resolvedName = props.name\n      ? props.name\n      : props.textNodes.map((textNode) => textNode.content).join('');\n\n    const frame = makeRect(0, 0, layout.width, layout.height);\n    const layer = makeTextLayer(this.platformBridge)(\n      frame,\n      resolvedName,\n      props.textNodes,\n      style,\n      props.resizingConstraint,\n      props.shadows,\n    );\n\n    const resolvedTextStyle = TextStyles(() => this.platformBridge).resolve(textStyle);\n    if (resolvedTextStyle) {\n      if (!layer.style) {\n        layer.style = resolvedTextStyle.sketchStyle;\n      }\n      layer.sharedStyleID = resolvedTextStyle.sharedObjectID;\n    }\n\n    return [layer];\n  }\n}\n"
  },
  {
    "path": "src/renderers/ViewRenderer.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport { SketchRenderer } from './SketchRenderer';\nimport { makeRect } from '../jsonUtils/models';\nimport { makeRectShapeLayer, makeShapeGroup } from '../jsonUtils/shapeLayers';\nimport { TreeNode } from '../types';\nimport { createBorders } from '../jsonUtils/borders';\nimport { hasAnyDefined } from '../utils/hasAnyDefined';\nimport { Props } from '../components/View';\n\nconst VISIBLE_STYLES = [\n  'shadowColor',\n  'shadowOffset',\n  'shadowOpacity',\n  'shadowRadius',\n  'shadowSpread',\n  'backgroundColor',\n  'borderColor',\n  'borderTopColor',\n  'borderRightColor',\n  'borderBottomColor',\n  'borderLeftColor',\n  'borderStyle',\n  'borderTopStyle',\n  'borderRightStyle',\n  'borderBottomStyle',\n  'borderLeftStyle',\n  'borderWidth',\n  'borderTopWidth',\n  'borderRightWidth',\n  'borderBottomWidth',\n  'borderLeftWidth',\n];\n\nconst OVERFLOW_STYLES = ['overflow', 'overflowX', 'overflowY'];\n\nexport class ViewRenderer extends SketchRenderer {\n  getDefaultGroupName(_props: Props) {\n    return 'View';\n  }\n\n  renderBackingLayers({\n    layout,\n    style,\n    props,\n  }: TreeNode<Props>): (\n    | FileFormat.ShapePath\n    | FileFormat.Rectangle\n    | FileFormat.SymbolMaster\n    | FileFormat.Group\n    | FileFormat.Polygon\n    | FileFormat.Star\n    | FileFormat.Triangle\n    | FileFormat.ShapeGroup\n    | FileFormat.Text\n    | FileFormat.SymbolInstance\n    | FileFormat.Slice\n    | FileFormat.Hotspot\n    | FileFormat.Bitmap\n  )[] {\n    let layers: FileFormat.ShapeGroup[] = [];\n    // NOTE(lmr): the group handles the position, so we just care about width/height here\n    const {\n      borderTopLeftRadius = 0,\n      borderTopRightRadius = 0,\n      borderBottomRightRadius = 0,\n      borderBottomLeftRadius = 0,\n    } = style;\n\n    if (!hasAnyDefined(style, VISIBLE_STYLES)) {\n      return layers;\n    }\n\n    const frame = makeRect(0, 0, layout.width, layout.height);\n    const radii = [\n      borderTopLeftRadius,\n      borderTopRightRadius,\n      borderBottomRightRadius,\n      borderBottomLeftRadius,\n    ];\n    const shapeLayer = makeRectShapeLayer(\n      0,\n      0,\n      layout.width,\n      layout.height,\n      radii,\n      props.resizingConstraint,\n    );\n\n    const content = makeShapeGroup(frame, [shapeLayer], style, props.shadows);\n\n    if (hasAnyDefined(style, OVERFLOW_STYLES)) {\n      if (\n        style.overflow === 'hidden' ||\n        style.overflow === 'scroll' ||\n        style.overflowX === 'hidden' ||\n        style.overflowX === 'scroll' ||\n        style.overflowY === 'hidden' ||\n        style.overflowY === 'scroll'\n      ) {\n        content.hasClippingMask = true;\n      }\n    }\n\n    const contents = createBorders(content, layout, style);\n\n    layers = layers.concat(contents);\n\n    return layers;\n  }\n}\n"
  },
  {
    "path": "src/renderers/index.ts",
    "content": "export { ArtboardRenderer as sketch_artboard } from './ArtboardRenderer';\nexport { ImageRenderer as sketch_image } from './ImageRenderer';\nexport { SvgRenderer as sketch_svg } from './SvgRenderer';\nexport { TextRenderer as sketch_text } from './TextRenderer';\nexport { ViewRenderer as sketch_view } from './ViewRenderer';\nexport { SymbolInstanceRenderer as sketch_symbolinstance } from './SymbolInstanceRenderer';\nexport { SymbolMasterRenderer as sketch_symbolmaster } from './SymbolMasterRenderer';\n"
  },
  {
    "path": "src/resets.ts",
    "content": "import { SketchDocumentData, SketchPage } from './types';\nimport { isNativeDocument } from './utils/isNativeDocument';\nimport { isNativeSymbolsPage } from './utils/isNativeSymbolsPage';\n\nexport const resetLayer = (container: SketchDocumentData | SketchPage) => {\n  if (isNativeDocument(container)) {\n    resetDocument(container);\n    return;\n  }\n  const layers = container.children();\n  // Skip last child since it is the container itself\n  for (let l = 0; l < layers.length - 1; l += 1) {\n    const layer = layers[l];\n    layer.removeFromParent();\n  }\n};\n\n// Clear out all document pages and layers\nexport const resetDocument = (documentData: SketchDocumentData) => {\n  // Get Pages and delete them all (Except Symbols Page)\n  const pages = documentData.pages();\n  for (let index = pages.length - 1; index >= 0; index -= 1) {\n    const page = pages[index];\n    // Don't delete symbols page\n    if (!isNativeSymbolsPage(page)) {\n      if (pages.length > 1) {\n        documentData.removePageAtIndex(index);\n      } else {\n        resetLayer(page);\n      }\n    }\n  }\n};\n"
  },
  {
    "path": "src/sharedStyles/TextStyles.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport {\n  SketchDocumentData,\n  SketchDocument,\n  WrappedSketchDocument,\n  TextStyle,\n  PlatformBridge,\n} from '../types';\nimport { getSketchVersion } from '../utils/getSketchVersion';\nimport { hashStyle } from '../utils/hashStyle';\nimport { getDocument } from '../utils/getDocument';\nimport { sharedTextStyles } from '../utils/sharedTextStyles';\nimport { makeTextStyle } from '../jsonUtils/textLayers';\nimport { pick } from '../utils/pick';\nimport { INHERITABLE_FONT_STYLES } from '../utils/constants';\n\ntype MurmurHash = string;\n\ntype RegisteredStyle = {\n  cssStyle: TextStyle;\n  name: string;\n  sketchStyle: FileFormat.Style;\n  sharedObjectID: FileFormat.Uuid;\n};\n\ntype StyleHash = { [key: string]: RegisteredStyle };\n\ntype Options = {\n  clearExistingStyles?: boolean;\n  document?: SketchDocumentData | SketchDocument | WrappedSketchDocument;\n};\n\nlet _styles: StyleHash = {};\nconst _byName: { [key: string]: MurmurHash } = {};\n\nexport const TextStyles = (getDefaultBridge: () => PlatformBridge) => ({\n  registerStyle(\n    name: string,\n    style: TextStyle,\n    platformBridge: PlatformBridge = getDefaultBridge(),\n  ) {\n    const safeStyle = pick(style, INHERITABLE_FONT_STYLES);\n    const hash = hashStyle(safeStyle);\n    const sketchStyle = makeTextStyle(platformBridge)(safeStyle);\n    const sharedObjectID = sharedTextStyles.addStyle(name, sketchStyle);\n\n    // FIXME(gold): side effect :'(\n    _byName[name] = hash;\n\n    _styles[hash] = {\n      cssStyle: safeStyle,\n      name,\n      sketchStyle,\n      sharedObjectID,\n    };\n  },\n\n  create(\n    styles: { [key: string]: TextStyle },\n    options: Options = {},\n    platformBridge: PlatformBridge = getDefaultBridge(),\n  ): StyleHash {\n    const { clearExistingStyles, document } = options;\n\n    const doc = getDocument(document);\n\n    const sketchVersion = getSketchVersion();\n\n    if (sketchVersion !== 'NodeJS' && sketchVersion < 50) {\n      if (doc) {\n        doc.showMessage('💎 Requires Sketch 50+ 💎');\n      }\n      return {};\n    }\n\n    sharedTextStyles.setDocument(doc);\n\n    if (clearExistingStyles) {\n      _styles = {};\n      sharedTextStyles.setStyles([]);\n    }\n\n    Object.keys(styles).forEach((name) => this.registerStyle(name, styles[name], platformBridge));\n\n    return _styles;\n  },\n\n  resolve(style?: TextStyle): RegisteredStyle | undefined {\n    if (!style) {\n      return undefined;\n    }\n    const safeStyle = pick(style, INHERITABLE_FONT_STYLES);\n    const hash = hashStyle(safeStyle);\n\n    return _styles[hash];\n  },\n\n  get(\n    name: string,\n    document?: SketchDocumentData | SketchDocument | WrappedSketchDocument,\n  ): TextStyle | undefined {\n    const hash = _byName[name];\n    const style = _styles[hash];\n\n    if (style) {\n      return style.cssStyle;\n    }\n\n    return sharedTextStyles.getStyle(name, document ? getDocument(document) : undefined);\n  },\n\n  clear(): void {\n    _styles = {};\n    sharedTextStyles.setStyles([]);\n  },\n\n  toJSON(): FileFormat.SharedStyle[] {\n    return Object.keys(_styles).map((k) => ({\n      _class: 'sharedStyle',\n      do_objectID: _styles[k].sharedObjectID,\n      name: _styles[k].name,\n      value: _styles[k].sketchStyle,\n    }));\n  },\n\n  styles() {\n    return _styles;\n  },\n});\n"
  },
  {
    "path": "src/stylesheet/expandStyle.ts",
    "content": "import { RawStyle, Style } from './types';\n\nconst { hasOwnProperty } = Object.prototype;\n\nconst styleShortHands: { [key: string]: { [subKey: string]: boolean } } = {\n  borderColor: {\n    borderTopColor: true,\n    borderRightColor: true,\n    borderBottomColor: true,\n    borderLeftColor: true,\n  },\n  borderRadius: {\n    borderTopLeftRadius: true,\n    borderTopRightRadius: true,\n    borderBottomRightRadius: true,\n    borderBottomLeftRadius: true,\n  },\n  borderStyle: {\n    borderTopStyle: true,\n    borderRightStyle: true,\n    borderBottomStyle: true,\n    borderLeftStyle: true,\n  },\n  borderWidth: {\n    borderTopWidth: true,\n    borderRightWidth: true,\n    borderBottomWidth: true,\n    borderLeftWidth: true,\n  },\n  margin: {\n    marginTop: true,\n    marginRight: true,\n    marginBottom: true,\n    marginLeft: true,\n  },\n  marginHorizontal: {\n    marginRight: true,\n    marginLeft: true,\n  },\n  marginVertical: {\n    marginTop: true,\n    marginBottom: true,\n  },\n  overflow: {\n    overflowX: true,\n    overflowY: true,\n  },\n  padding: {\n    paddingTop: true,\n    paddingRight: true,\n    paddingBottom: true,\n    paddingLeft: true,\n  },\n  paddingHorizontal: {\n    paddingRight: true,\n    paddingLeft: true,\n  },\n  paddingVertical: {\n    paddingTop: true,\n    paddingBottom: true,\n  },\n  textDecorationLine: {\n    textDecoration: true,\n  },\n  writingDirection: {\n    direction: true,\n  },\n};\n\n/**\n * Alpha-sort properties, apart from shorthands – they must appear before the\n * longhand properties that they expand into. This lets more specific styles\n * override less specific styles, whatever the order in which they were\n * originally declared.\n */\nconst sortProps = (propsArray: string[]) =>\n  propsArray.sort((a, b) => {\n    const expandedA = styleShortHands[a];\n    const expandedB = styleShortHands[b];\n    if (expandedA && expandedA[b]) {\n      return -1;\n    }\n    if (expandedB && expandedB[a]) {\n      return 1;\n    }\n    return a < b ? -1 : a > b ? 1 : 0;\n  });\n\n/**\n * Expand the shorthand properties to isolate every declaration from the others.\n */\nexport const expandStyle = (style: RawStyle): Style => {\n  if (!style) return style;\n  const propsArray = Object.keys(style);\n  const sortedProps = sortProps(propsArray);\n  const resolvedStyle: Style = {};\n\n  for (let i = 0; i < sortedProps.length; i++) {\n    const key = sortedProps[i];\n    const expandedProps = styleShortHands[key];\n    const value = style[key];\n\n    if (expandedProps) {\n      for (const propName in expandedProps) {\n        if (hasOwnProperty.call(expandedProps, propName)) {\n          resolvedStyle[propName] = value;\n        }\n      }\n    } else {\n      resolvedStyle[key] = value;\n    }\n  }\n  return resolvedStyle;\n};\n"
  },
  {
    "path": "src/stylesheet/index.ts",
    "content": "import { expandStyle } from './expandStyle';\nimport {\n  RawStyle,\n  RawStyles,\n  Rules,\n  Style,\n  StyleId,\n  StyleSheetInstance,\n  Transform,\n  UserStyle,\n  UserStyles,\n} from './types';\n\nlet _id = 0;\nconst guid = () => _id++;\nconst declarationRegistry: { [id: string]: Style } = {};\n\nconst extractRules = (style: RawStyle): Rules => {\n  const declarations: { [key: string]: any } = {};\n\n  Object.keys(style).forEach((key) => {\n    if (key[0] === ':') {\n      // pseudo style. ignore for now.\n    } else if (key[0] === '@') {\n      // Media query. ignore for now.\n    } else {\n      declarations[key] = style[key];\n    }\n  });\n\n  return {\n    declarations,\n  };\n};\n\nconst registerStyle = (style: RawStyle): StyleId => {\n  // TODO(lmr):\n  // do \"proptype\"-like validation here in non-production build\n  const id = guid();\n  const rules = extractRules(style);\n  declarationRegistry[id] = expandStyle(rules.declarations);\n  return id;\n};\n\nconst getStyle = (id: StyleId): Style => declarationRegistry[id];\n\nconst create = (styles: RawStyles): StyleSheetInstance => {\n  const result: StyleSheetInstance = {};\n  Object.keys(styles).forEach((key) => {\n    result[key] = registerStyle(styles[key]);\n  });\n  return result;\n};\n\nconst mergeTransforms = (a?: Transform, b?: Transform): Transform | undefined => {\n  if (!a || a.length === 0) return b; // in this case, a has nothing to contribute.\n  const result: Transform = [];\n  const transformsInA: { [key: string]: number } = a.reduce((hash, t) => {\n    const key = Object.keys(t)[0];\n    result.push(t);\n    hash[key] = result.length - 1;\n    return hash;\n  }, {});\n  (b || []).forEach((t) => {\n    const key = Object.keys(t)[0];\n    const index = transformsInA[key];\n    if (index !== undefined) {\n      result[index] = t;\n    } else {\n      result.push(t);\n    }\n  });\n  return result;\n};\n\n// merge two style hashes together. Sort of like `Object.assign`, but is aware of `transform` as a\n// special case.\n// NOTE(lmr): mutates the first argument!\nconst mergeStyle = (a: Style, b: Style): Style => {\n  Object.keys(b).forEach((key) => {\n    if (key === 'transform') {\n      a[key] = mergeTransforms(a[key], b[key]);\n    } else {\n      a[key] = b[key];\n    }\n  });\n  return a;\n};\n\nconst flattenStyle = (input?: UserStyles | null): Style | undefined => {\n  if (Array.isArray(input)) {\n    let acc: Style = {};\n    return input.reduce<Style>((prev, val) => mergeStyle(prev, flattenStyle(val) || {}), acc);\n  }\n  if (typeof input === 'number') {\n    return getStyle(input);\n  }\n  if (!input) {\n    // input is falsy, so we skip it by returning undefined\n    return undefined;\n  }\n  return expandStyle(input);\n};\n\n/**\n * A StyleSheet is an abstraction similar to CSS StyleSheets. WIP.\n */\nexport const StyleSheet = {\n  hairlineWidth: 1, // TODO(lmr): should this be something different?\n  absoluteFill: registerStyle({\n    position: 'absolute',\n    top: 0,\n    left: 0,\n    bottom: 0,\n    right: 0,\n  }),\n  create,\n  flatten: flattenStyle,\n  resolve: (style: UserStyle) => ({ style: flattenStyle(style) }),\n};\n"
  },
  {
    "path": "src/stylesheet/types.ts",
    "content": "export type Transform = { [key: string]: number }[];\nexport type Style = {\n  resizeMode?: 'contain' | 'cover' | 'stretch' | 'center' | 'repeat' | 'none';\n  height?: number | null;\n  width?: number | null;\n  transform?: Transform;\n  [key: string]: unknown;\n};\nexport type StyleId = number;\nexport type RawStyle = { [key: string]: any };\nexport type RawStyles = { [key: string]: RawStyle };\nexport type UserStyle = RawStyle | StyleId;\nexport type UserStyles = Array<UserStyle> | UserStyle;\nexport type Rules = { declarations: { [key: string]: RawStyle } };\nexport type StyleSheetInstance = { [key: string]: StyleId };\n"
  },
  {
    "path": "src/symbol.tsx",
    "content": "import * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport { fromSJSON } from './jsonUtils/sketchJson/fromSJSON';\nimport { toSJSON } from './jsonUtils/sketchJson/toSJSON';\nimport { StyleSheet } from './stylesheet';\nimport { generateID } from './jsonUtils/models';\nimport { ViewStylePropTypes } from './components/ViewStylePropTypes';\nimport { ResizingConstraintPropTypes } from './components/ResizingConstraintPropTypes';\nimport { buildTree } from './buildTree';\nimport { flexToSketchJSON } from './flexToSketchJSON';\nimport { renderLayers } from './render';\nimport { resetLayer } from './resets';\nimport { getDocumentData } from './utils/getDocument';\nimport { SketchDocumentData, SketchDocument, WrappedSketchDocument, PlatformBridge } from './types';\nimport { getSketchVersion } from './utils/getSketchVersion';\n\nlet id = 0;\nconst nextId = () => ++id;\n\nconst displayName = (Component: React.ComponentType<any>): string =>\n  Component.displayName || Component.name || `UnknownSymbol${nextId()}`;\n\nlet hasInitialized = false;\nconst symbolsRegistry: { [name: string]: FileFormat.SymbolMaster } = {};\nlet existingSymbols: FileFormat.SymbolMaster[] = [];\nconst layers: { [symbolID: string]: any } = {};\n\nfunction msListToArray<T>(pageList: T[]): T[] {\n  const out = [];\n  for (let i = 0; i < pageList.length; i++) {\n    out.push(pageList[i]);\n  }\n  return out;\n}\n\nconst getSymbolsPage = (documentData: SketchDocumentData) =>\n  documentData.symbolsPageOrCreateIfNecessary();\n\nfunction exists(x: FileFormat.SymbolMaster | undefined | null): x is FileFormat.SymbolMaster {\n  return !!x;\n}\n\nconst getExistingSymbols = (documentData: SketchDocumentData) => {\n  if (!hasInitialized) {\n    hasInitialized = true;\n\n    const symbolsPage = getSymbolsPage(documentData);\n\n    existingSymbols = msListToArray(symbolsPage.layers())\n      .map((x) => {\n        const symbolJson = toSJSON(x);\n        if (!symbolJson || symbolJson._class !== 'symbolMaster') {\n          return undefined;\n        }\n        layers[symbolJson.symbolID] = x;\n        return symbolJson;\n      })\n      .filter(exists);\n\n    existingSymbols.forEach((symbolMaster) => {\n      if (symbolMaster._class !== 'symbolMaster') return;\n      if (symbolMaster.name in symbolsRegistry) return;\n      symbolsRegistry[symbolMaster.name] = symbolMaster;\n    });\n  }\n  return existingSymbols;\n};\n\nexport const injectSymbols = (\n  document?: SketchDocumentData | SketchDocument | WrappedSketchDocument,\n) => {\n  if (getSketchVersion() === 'NodeJS') {\n    console.error('Cannot inject symbols in NodeJS');\n    return;\n  }\n\n  // if hasInitialized is false then makeSymbol has not yet been called\n  // so we don't have anything to inject\n  if (hasInitialized) {\n    const documentData = getDocumentData(document);\n\n    if (!documentData) {\n      return;\n    }\n\n    const currentPage = documentData.currentPage();\n\n    const symbolsPage = getSymbolsPage(documentData);\n\n    let left = 0;\n    Object.keys(symbolsRegistry).forEach((key) => {\n      const symbolMaster = symbolsRegistry[key];\n      symbolMaster.frame.y = 0;\n      symbolMaster.frame.x = left;\n      left += symbolMaster.frame.width + 20;\n\n      const newLayer = fromSJSON(symbolMaster, '119');\n      layers[symbolMaster.symbolID] = newLayer;\n    });\n\n    // Clear out page layers to prepare for re-render\n    resetLayer(symbolsPage);\n\n    renderLayers(\n      Object.keys(layers).map((k) => layers[k]),\n      symbolsPage,\n    );\n\n    documentData.setCurrentPage(currentPage);\n  }\n};\n\nconst SymbolInstancePropTypes = {\n  style: PropTypes.shape(ViewStylePropTypes),\n  name: PropTypes.string,\n  overrides: PropTypes.objectOf(PropTypes.oneOfType([PropTypes.string, PropTypes.func])),\n  resizingConstraint: PropTypes.shape({\n    ...ResizingConstraintPropTypes,\n  }),\n};\n\nexport type SymbolInstanceProps = PropTypes.InferProps<typeof SymbolInstancePropTypes>;\n\nexport const createSymbolInstanceClass = (symbolMaster: FileFormat.SymbolMaster) => {\n  return class SymbolInstance extends React.Component<SymbolInstanceProps> {\n    static displayName = `SymbolInstance(${symbolMaster.name})`;\n\n    static propTypes = SymbolInstancePropTypes;\n\n    static symbolID = symbolMaster.symbolID;\n\n    static masterName = symbolMaster.name;\n\n    render() {\n      return (\n        <sketch_symbolinstance\n          symbolID={symbolMaster.symbolID}\n          name={this.props.name || symbolMaster.name}\n          style={StyleSheet.flatten(this.props.style)}\n          resizingConstraint={this.props.resizingConstraint}\n          overrides={this.props.overrides}\n        />\n      );\n    }\n  };\n};\n\nconst SymbolMasterPropTypes = {\n  style: PropTypes.shape(ViewStylePropTypes),\n  name: PropTypes.string,\n};\n\nexport type SymbolMasterProps = PropTypes.InferProps<typeof SymbolMasterPropTypes>;\n\nexport const makeSymbol = (bridge: PlatformBridge) => (\n  Component: React.ComponentType<any>,\n  symbolProps: string | SymbolMasterProps,\n  document?: SketchDocumentData | SketchDocument | WrappedSketchDocument,\n) => {\n  if (!hasInitialized && getSketchVersion() !== 'NodeJS') {\n    const documentData = getDocumentData(document);\n    if (documentData) {\n      getExistingSymbols(documentData);\n    }\n  }\n\n  const masterName =\n    (typeof symbolProps === 'string' ? symbolProps : (symbolProps || {}).name) ||\n    displayName(Component);\n  const existingSymbol = existingSymbols.find((symbolMaster) => symbolMaster.name === masterName);\n  const symbolID = existingSymbol\n    ? existingSymbol.symbolID\n    : generateID(`symbolID:${masterName}`, !!masterName);\n\n  const symbolMaster = flexToSketchJSON(bridge)(\n    buildTree(bridge)(\n      <sketch_symbolmaster\n        {...(typeof symbolProps !== 'string' ? symbolProps || {} : {})}\n        symbolID={symbolID}\n        name={masterName}\n      >\n        <Component />\n      </sketch_symbolmaster>,\n    ),\n  ) as FileFormat.SymbolMaster;\n\n  symbolsRegistry[symbolID] = symbolMaster;\n  return createSymbolInstanceClass(symbolMaster);\n};\n\nfunction tryGettingSymbolMasterInDocumentByName(\n  name: string,\n  document?: SketchDocumentData | SketchDocument | WrappedSketchDocument,\n): FileFormat.SymbolMaster | undefined {\n  const documentData = getDocumentData(document);\n\n  if (!documentData) {\n    return undefined;\n  }\n\n  const symbols = documentData.symbolMap();\n  const symbol = Object.keys(symbols).find((k) => symbols[k].name() === name);\n\n  if (!symbol) {\n    return undefined;\n  }\n\n  return toSJSON(symbol) as FileFormat.SymbolMaster;\n}\n\nfunction tryGettingSymbolMasterInDocumentById(\n  symbolID: string,\n  document?: SketchDocumentData | SketchDocument | WrappedSketchDocument,\n): FileFormat.SymbolMaster | undefined {\n  const documentData = getDocumentData(document);\n\n  if (!documentData) {\n    return undefined;\n  }\n\n  const symbol = documentData.symbolMap()[symbolID];\n\n  if (!symbol) {\n    return undefined;\n  }\n\n  return toSJSON(symbol) as FileFormat.SymbolMaster;\n}\n\nexport const getSymbolMasterByName = (\n  name: string,\n  document?: SketchDocumentData | SketchDocument | WrappedSketchDocument,\n): FileFormat.SymbolMaster | undefined => {\n  const symbolID = name\n    ? Object.keys(symbolsRegistry).find((key) => String(symbolsRegistry[key].name) === name)\n    : '';\n\n  if (typeof symbolID === 'undefined' && name && getSketchVersion() !== 'NodeJS') {\n    return tryGettingSymbolMasterInDocumentByName(name, document);\n  }\n\n  if (typeof symbolID === 'undefined') {\n    throw new Error('##FIXME## NO MASTER FOR THIS SYMBOL NAME');\n  }\n\n  return symbolsRegistry[symbolID];\n};\n\nexport const getSymbolMasterById = (\n  symbolID?: string,\n  document?: SketchDocumentData | SketchDocument | WrappedSketchDocument,\n): FileFormat.SymbolMaster | undefined => {\n  let symbolMaster = symbolID ? symbolsRegistry[symbolID] : undefined;\n\n  if (typeof symbolMaster === 'undefined' && symbolID && getSketchVersion() !== 'NodeJS') {\n    symbolMaster = tryGettingSymbolMasterInDocumentById(symbolID, document);\n  }\n\n  if (typeof symbolMaster === 'undefined') {\n    throw new Error('##FIXME## NO MASTER WITH THAT SYMBOL ID');\n  }\n\n  return symbolMaster;\n};\n\nexport const getSymbolComponentById = (\n  symbolID: string,\n  document?: SketchDocumentData | SketchDocument | WrappedSketchDocument,\n) => {\n  const symbolMaster = getSymbolMasterById(symbolID, document);\n  if (!symbolMaster) {\n    return undefined;\n  }\n  return createSymbolInstanceClass(symbolMaster);\n};\n\nexport const getSymbolComponentByName = (\n  masterName: string,\n  document?: SketchDocumentData | SketchDocument | WrappedSketchDocument,\n) => {\n  const symbolMaster = getSymbolMasterByName(masterName, document);\n  if (!symbolMaster) {\n    return undefined;\n  }\n  return createSymbolInstanceClass(symbolMaster);\n};\n"
  },
  {
    "path": "src/types/globals.d.ts",
    "content": "declare const context: any;\ndeclare const NSString: any;\ndeclare const NSUTF8StringEncoding: any;\ndeclare const MSSVGImporter: any;\ndeclare const MSSharedStyle: any;\ndeclare const NSData: any;\ndeclare const NSURL: any;\ndeclare const NSMakeRange: any;\ndeclare const NSImage: any;\ndeclare const MSImageData: any;\ndeclare const NSDataBase64EncodingEndLineWithCarriageReturn: any;\ndeclare const NSFontTraitsAttribute: any;\ndeclare const NSFontSymbolicTrait: any;\ndeclare const NSFontItalicTrait: any;\ndeclare const NSFontCondensedTrait: any;\ndeclare const NSFontWeightTrait: any;\ndeclare const NSFontManager: any;\ndeclare const NSArray: any;\ndeclare const NSFont: any;\ndeclare const NSFontWeightRegular: any;\ndeclare const NSMutableParagraphStyle: any;\ndeclare const NSAttributedString: any;\ndeclare const NSMutableAttributedString: any;\ndeclare const CGSizeMake: any;\ndeclare const NSStringDrawingUsesLineFragmentOrigin: any;\ndeclare const NSBundle: any;\ndeclare const NSDocumentController: any;\ndeclare const MSPage: any;\ndeclare const MOPointer: any;\ndeclare const MSJSONDictionaryUnarchiver: any;\ndeclare const MSJSONDataArchiver: any;\ndeclare const NSMakeRect: any;\ndeclare const MSLayerGroup: any;\ndeclare const NSISOLatin1StringEncoding: any;\n"
  },
  {
    "path": "src/types/index.ts",
    "content": "import * as PropTypes from 'prop-types';\nimport {\n  ViewStylePropTypes,\n  Color as ColorProp,\n  BorderStyle as BorderProp,\n  Overflow as OverflowProp,\n} from '../components/ViewStylePropTypes';\nimport { TextStylePropTypes } from '../components/TextStylePropTypes';\n\n// Sketchy things\nexport type SketchLayer = any;\n\nexport type WrappedSketchLayer = {\n  sketchObject: SketchLayer;\n};\n\nexport type MSArray<T> = {\n  [key: number]: T;\n  length: number;\n};\n\ntype NSString = any;\n\nexport type SketchPage = {\n  name: () => NSString;\n  setName: (name: string) => void;\n  layers: () => Array<SketchLayer>;\n  children: () => Array<SketchLayer>;\n};\n\nexport type SketchStyle = any;\n\nexport type SketchSharedStyleContainer = {\n  objects: () => any[];\n  setObjects: (objects: Array<SketchStyle>) => void;\n  addSharedStyleWithName_firstInstance: (name: string, ins: SketchStyle) => any;\n  addSharedObject: (ins: any) => any;\n};\n\ntype MSGradient = any;\ntype MSColor = any;\n\ntype SketchAssetCollection = {\n  colors: () => Array<MSColor>;\n  gradients: () => Array<MSGradient>;\n};\n\nexport type SketchDocumentData = {\n  delegate: () => SketchDocument;\n  assets: () => SketchAssetCollection;\n  layerStyles: () => void;\n  layerTextStyles: () => SketchSharedStyleContainer;\n  layerSymbols: () => void;\n  symbolMap: () => { [symbolID: string]: SketchLayer };\n  removePageAtIndex: (index: number) => void;\n  addBlankPage: () => SketchPage;\n  currentPage: () => SketchPage;\n  setCurrentPage: (page: SketchPage) => void;\n  pages: () => MSArray<SketchPage>;\n  symbolsPageOrCreateIfNecessary: () => SketchPage;\n};\n\nexport type SketchDocument = {\n  documentData: () => SketchDocumentData;\n  showMessage: (message: string) => void;\n};\n\nexport type WrappedSketchDocument = {\n  sketchObject: SketchDocument | SketchDocumentData;\n};\n\nexport type SketchContext = {\n  document: SketchDocument;\n  actionContext: {\n    document?: SketchDocument;\n  };\n};\n\n// Reacty things\n\nexport type Size = { width: number; height: number };\n\nexport type LayoutInfo = {\n  width: number;\n  height: number;\n  top: number;\n  left: number;\n  right: number;\n  bottom: number;\n  direction?: 'ltr' | 'rtl';\n};\n\n// undefined: max content\n// exactly: fill available space\n// at-most: fit content\nexport type MeasureMode = 'undefined' | 'exactly' | 'at-most';\n\nexport type Color = PropTypes.InferType<typeof ColorProp>;\nexport type BorderStyle = PropTypes.InferType<typeof BorderProp>;\nexport type Overflow = PropTypes.InferType<typeof OverflowProp>;\nexport type ViewStyle = PropTypes.InferProps<typeof ViewStylePropTypes> & { color?: string };\nexport type TextStyle = PropTypes.InferProps<typeof TextStylePropTypes> & { color?: string };\n\nexport type TextNode = { content: string; textStyles: TextStyle };\n\nexport type TreeNode<Props = any> = {\n  type: string;\n  style: ViewStyle;\n  textStyle?: TextStyle;\n  layout: LayoutInfo;\n  props: Props & { textNodes: TextNode[] };\n  children?: Array<TreeNode | string>;\n};\n\nexport type ResizeConstraints = {\n  top?: boolean;\n  right?: boolean;\n  bottom?: boolean;\n  left?: boolean;\n  fixedHeight?: boolean;\n  fixedWidth?: boolean;\n};\n\nexport type PlatformBridge = {\n  createStringMeasurer(textNodes: TextNode[], maxWidth: number): Size;\n  findFontName(style: TextStyle): string;\n  makeImageDataFromUrl(url?: string): string;\n};\n"
  },
  {
    "path": "src/types/intrinsic.d.ts",
    "content": "declare module JSX {\n  interface IntrinsicElements {\n    sketch_symbolinstance: any;\n    sketch_symbolmaster: any;\n    sketch_view: any;\n    sketch_text: any;\n    sketch_page: any;\n    sketch_image: any;\n    sketch_document: any;\n    sketch_artboard: any;\n    sketch_svg: any;\n    svg_circle: any;\n    svg_clipPath: any;\n    svg_defs: any;\n    svg_ellipse: any;\n    svg_g: any;\n    svg_image: any;\n    svg_line: any;\n    svg_linearGradient: any;\n    svg_path: any;\n    svg_pattern: any;\n    svg_polygon: any;\n    svg_polyline: any;\n    svg_radialGradient: any;\n    svg_rect: any;\n    svg_stop: any;\n    svg_symbol: any;\n    svg_text: any;\n    svg_textPath: any;\n    svg_tspan: any;\n    svg_use: any;\n  }\n}\n"
  },
  {
    "path": "src/types/js-sha1.d.ts",
    "content": "declare module 'js-sha1' {\n  function sha1<T>(dest: string | Array<T> | ArrayBuffer | Uint8Array): string;\n\n  namespace sha1 {\n    export function hex(arg: string): string;\n    export function update<T>(arg: string | Array<T> | Uint8Array | ArrayBuffer): string;\n    export function array(): Uint8Array;\n    export function digest(): Uint8Array;\n    export function arrayBuffer(): ArrayBuffer;\n  }\n\n  export = sha1;\n}\n"
  },
  {
    "path": "src/types/murmur2js.d.ts",
    "content": "declare module 'murmur2js' {\n  function hash(content: string): string;\n  export = hash;\n}\n"
  },
  {
    "path": "src/types/node-sketch-bridge.d.ts",
    "content": "declare module 'node-sketch-bridge';\n"
  },
  {
    "path": "src/types/normalize-css-color.d.ts",
    "content": "declare module 'normalize-css-color' {\n  export default function normalize(color?: string | number | null): number | null;\n  export function rgba(color: number): { r: number; g: number; b: number; a: number };\n}\n"
  },
  {
    "path": "src/utils/Context.ts",
    "content": "type Styles = Object;\n\nexport class Context {\n  styles: Styles;\n\n  staged: Array<Styles>;\n\n  constructor(styles: Styles = {}) {\n    this.styles = styles;\n    this.staged = [];\n  }\n\n  addInheritableStyles(styles: Styles) {\n    this.staged.push(styles);\n  }\n\n  forChildren() {\n    if (this.staged.length === 0) {\n      return new Context(this.styles);\n    }\n    const styles = Object.assign({}, this.styles, ...this.staged);\n    return new Context(styles);\n  }\n\n  getInheritedStyles() {\n    return this.styles;\n  }\n}\n"
  },
  {
    "path": "src/utils/constants.ts",
    "content": "export const INHERITABLE_FONT_STYLES = [\n  'color',\n  'fontFamily',\n  'fontSize',\n  'fontStyle',\n  'fontWeight',\n  'textAlign',\n  'textDecoration',\n  'textShadowColor',\n  'textShadowOffset',\n  'textShadowOpacity',\n  'textShadowRadius',\n  'textShadowSpread',\n  'textTransform',\n  'letterSpacing',\n  'lineHeight',\n  'writingDirection',\n  'paragraphSpacing',\n] as const;\n\n// Only components that are allowed as children of <Text> components\nexport const VALID_TEXT_CHILDREN_TYPES = ['text', 'sketch_text'];\n"
  },
  {
    "path": "src/utils/createStringMeasurer.ts",
    "content": "import { TextNode, Size, PlatformBridge } from '../types';\n\nfunction isNaN(num: number): boolean {\n  // If the value is obj-c NaN, the only way to check for it is by comparing\n  // width to itself (because NaN !== NaN)\n  // eslint-disable-next-line no-self-compare\n  return Number.isNaN(num) || num !== num;\n}\n\nexport const createStringMeasurer = (bridge: PlatformBridge) => (textNodes: TextNode[]) => (\n  width: number = 0,\n): Size => {\n  const sanitizedWidth = isNaN(width) ? 0 : width;\n\n  return textNodes.length > 0\n    ? bridge.createStringMeasurer(textNodes, sanitizedWidth)\n    : { width: sanitizedWidth, height: 0 };\n};\n"
  },
  {
    "path": "src/utils/getDocument.ts",
    "content": "import { SketchDocumentData, SketchContext, SketchDocument, WrappedSketchDocument } from '../types';\n\nexport const getDocumentDataFromContext = (ctx: SketchContext): SketchDocumentData =>\n  (\n    ctx.document ||\n    (ctx.actionContext || {}).document ||\n    NSDocumentController.sharedDocumentController().currentDocument()\n  ).documentData();\n\nexport const getDocumentDataFromContainer = (container?: any): SketchDocumentData => {\n  if (!container) {\n    return getDocumentDataFromContext(context);\n  }\n\n  return container.documentData();\n};\n\nexport const getDocument = (\n  document?: SketchDocumentData | SketchDocument | WrappedSketchDocument,\n): SketchDocument | undefined => {\n  const documentData = getDocumentData(document);\n  if (typeof documentData === 'undefined' || !('delegate' in documentData)) {\n    return documentData;\n  }\n\n  return documentData.delegate();\n};\n\nexport const getDocumentData = (\n  document?: SketchDocumentData | SketchDocument | WrappedSketchDocument,\n): SketchDocumentData | undefined => {\n  let nativeDocument: SketchDocumentData | SketchDocument | undefined;\n  let nativeDocumentData: SketchDocumentData;\n\n  if (!document && typeof context !== 'undefined') {\n    nativeDocument = getDocumentDataFromContext(context);\n  } else if (typeof document !== 'undefined' && 'sketchObject' in document) {\n    nativeDocument = document.sketchObject;\n  } else {\n    nativeDocument = document;\n  }\n\n  if (!nativeDocument) {\n    return undefined;\n  }\n\n  if ('documentData' in nativeDocument) {\n    nativeDocumentData = nativeDocument.documentData();\n  } else {\n    nativeDocumentData = nativeDocument;\n  }\n\n  return nativeDocumentData;\n};\n"
  },
  {
    "path": "src/utils/getImageDataFromURL.ts",
    "content": "import sha1 from 'js-sha1';\nimport { PlatformBridge } from '../types';\n\nexport const getImageDataFromURL = (bridge: PlatformBridge) => (\n  url?: string,\n): { data: string; sha1: string } => {\n  const data = bridge.makeImageDataFromUrl(url);\n\n  return {\n    data,\n    sha1: sha1(data),\n  };\n};\n"
  },
  {
    "path": "src/utils/getSketchVersion.ts",
    "content": "export function getSketchVersion(): number | 'NodeJS' {\n  if (typeof NSBundle !== 'undefined') {\n    return parseFloat(NSBundle.mainBundle().infoDictionary().CFBundleShortVersionString);\n  }\n  return 'NodeJS';\n}\n"
  },
  {
    "path": "src/utils/hasAnyDefined.ts",
    "content": "export const hasAnyDefined = (obj: { [key: string]: unknown }, names: readonly string[]): boolean =>\n  names.some((key) => obj[key] !== undefined);\n"
  },
  {
    "path": "src/utils/hashStyle.ts",
    "content": "import murmurHash from 'murmur2js';\nimport { sortObjectKeys } from './sortObjectKeys';\n\nexport const hashStyle = (obj: { [key: string]: unknown }): string => {\n  if (obj) {\n    return String(murmurHash(JSON.stringify(sortObjectKeys(obj))));\n  }\n  return '0';\n};\n"
  },
  {
    "path": "src/utils/isDefined.ts",
    "content": "export const isDefined = (value: unknown): value is number =>\n  value !== null && typeof value !== 'undefined';\n"
  },
  {
    "path": "src/utils/isNativeDocument.ts",
    "content": "import { SketchDocumentData } from '../types';\n\nexport const isNativeDocument = (container: unknown): container is SketchDocumentData =>\n  // @ts-ignore\n  container && typeof container.pages === 'function';\n"
  },
  {
    "path": "src/utils/isNativePage.ts",
    "content": "import { SketchPage } from '../types';\n\nexport const isNativePage = (container: unknown): container is SketchPage =>\n  container instanceof MSPage;\n"
  },
  {
    "path": "src/utils/isNativeSymbolsPage.ts",
    "content": "import { isNativePage } from './isNativePage';\n\n// NOTE: Must cast to string as page.name() returns a MSBoxedObject\nexport const isNativeSymbolsPage = (layer: unknown): boolean =>\n  isNativePage(layer) && String(layer.name()) === 'Symbols';\n"
  },
  {
    "path": "src/utils/pick.ts",
    "content": "export function pick<T, K extends keyof T>(obj: T, keys: readonly K[]): Pick<T, K> {\n  const ret: any = {};\n  keys.forEach((key) => {\n    if (obj[key] !== undefined) {\n      ret[key] = obj[key];\n    }\n  });\n  return ret;\n}\n"
  },
  {
    "path": "src/utils/processTransform/index.ts",
    "content": "import { LayoutInfo, ViewStyle } from '../../types';\nimport { parseTransformProp } from './parseTransformProp';\nimport { parseTransformOriginProp } from './parseTransformOriginProp';\n\nfunction closeEnough(a: number, b: number) {\n  return Math.abs(a - b) < 0.01;\n}\n\nfunction isRotation(a: number, b: number, c: number, d: number) {\n  return closeEnough(a, d) && closeEnough(c, -b) && closeEnough(a * d - c * b, 1);\n}\n\nconst rad2deg = 180 / Math.PI;\n\nfunction getRotation(a: number, b: number) {\n  const sketchFactor = -1;\n  const possibleRotation = Math.acos(a);\n  if (closeEnough(Math.sin(possibleRotation), b) || closeEnough(Math.sin(possibleRotation), -b)) {\n    return sketchFactor * possibleRotation * rad2deg;\n  }\n  return sketchFactor * (possibleRotation + Math.PI) * rad2deg;\n}\n\nexport function processTransform(\n  layout: LayoutInfo,\n  props: ViewStyle,\n): { rotation?: number; isFlippedVertical?: boolean; isFlippedHorizontal?: boolean } {\n  if (!props.transform) {\n    return {};\n  }\n\n  const origin = parseTransformOriginProp(layout, props.transformOrigin);\n  const [a, b, c, d, tx, ty] = parseTransformProp(props.transform, origin);\n\n  // apply translation\n  layout.top += ty;\n  layout.left += tx;\n\n  // look for a rotation\n  if (isRotation(a, b, c, d)) {\n    return {\n      rotation: getRotation(a, b),\n    };\n  }\n\n  // let's try to check if there is a reflection\n  // we are going to apply the same reflection and see if the result is a rotation\n\n  /**\n   * check if flipped vertically\n   * 1  0\n   * 0 -1\n   */\n  let _a = a;\n  let _b = -b;\n  let _c = c;\n  let _d = -d;\n\n  if (isRotation(_a, _b, _c, _d)) {\n    return {\n      rotation: getRotation(_a, _b),\n      isFlippedVertical: true,\n    };\n  }\n\n  /**\n   * check if flipped horizontally\n   * -1 0\n   *  0 1\n   */\n  _a = -a;\n  _b = b;\n  _c = -c;\n  _d = d;\n\n  if (isRotation(_a, _b, _c, _d)) {\n    return {\n      rotation: getRotation(_a, _b),\n      isFlippedHorizontal: true,\n    };\n  }\n\n  /**\n   * no need to check if flipped vertically and horizontally since it's a rotation\n   */\n\n  // didn't find any rotation or reflection\n  return {};\n}\n"
  },
  {
    "path": "src/utils/processTransform/matrix2D.ts",
    "content": "/**\n * based on\n * https://github.com/react-native-community/react-native-svg/blob/28235ea137a75097c011f11fee92bec8a97b4afa/lib/Matrix2D.js\n */\n\n/**\n * Represents an affine transformation matrix, and provides tools\n * for constructing and concatenating matrices.\n *\n * This matrix can be visualized as:\n *\n * [ a  c  tx\n *   b  d  ty\n *   0  0  1  ]\n *\n * Note the locations of b and c.\n * */\nexport class Matrix2D {\n  a: number;\n\n  b: number;\n\n  c: number;\n\n  d: number;\n\n  tx: number;\n\n  ty: number;\n\n  constructor(a?: number, b?: number, c?: number, d?: number, tx?: number, ty?: number) {\n    this.a = a === null || a === undefined ? 1 : a;\n    this.b = b || 0;\n    this.c = c || 0;\n    this.d = d === null || d === undefined ? 1 : d;\n    this.tx = tx || 0;\n    this.ty = ty || 0;\n  }\n\n  /**\n   * Set current matrix to new absolute matrix.\n   */\n  setTransform = (a?: number, b?: number, c?: number, d?: number, tx?: number, ty?: number) => {\n    this.a = a === null || a === undefined ? 1 : a;\n    this.b = b || 0;\n    this.c = c || 0;\n    this.d = d === null || d === undefined ? 1 : d;\n    this.tx = tx || 0;\n    this.ty = ty || 0;\n    return this;\n  };\n\n  /**\n   * Reset current matrix to an identity matrix.\n   * */\n  reset = () => {\n    this.a = 1;\n    this.d = 1;\n    this.b = 0;\n    this.c = 0;\n    this.tx = 0;\n    this.ty = 0;\n    return this;\n  };\n\n  /**\n   * Returns an array with current matrix values.\n   * */\n  toArray = () => [this.a, this.b, this.c, this.d, this.tx, this.ty];\n\n  /**\n   * Copies all properties from the specified matrix to this matrix.\n   */\n  copy = (matrix: Matrix2D) =>\n    this.setTransform(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty);\n\n  /**\n   * Clones current instance and returning a new matrix.\n   * */\n  clone = () => new Matrix2D(this.a, this.b, this.c, this.d, this.tx, this.ty);\n\n  /**\n   * Prepends the specified matrix properties to this matrix.\n   * This is the equivalent of multiplying `(specified matrix) * (this matrix)`.\n   * All parameters are required.\n   * */\n  prepend = (a: number, b: number, c: number, d: number, tx: number, ty: number) => {\n    const a1 = this.a;\n    const c1 = this.c;\n    const tx1 = this.tx;\n\n    this.a = a * a1 + c * this.b;\n    this.b = b * a1 + d * this.b;\n    this.c = a * c1 + c * this.d;\n    this.d = b * c1 + d * this.d;\n    this.tx = a * tx1 + c * this.ty + tx;\n    this.ty = b * tx1 + d * this.ty + ty;\n    return this;\n  };\n\n  /**\n   * Appends the specified matrix properties to this matrix. All parameters are required.\n   * This is the equivalent of multiplying `(this matrix) * (specified matrix)`.\n   * */\n  append = (a: number, b: number, c: number, d: number, tx: number, ty: number) => {\n    const a1 = this.a;\n    const b1 = this.b;\n    const c1 = this.c;\n    const d1 = this.d;\n    if (a !== 1 || b !== 0 || c !== 0 || d !== 1) {\n      this.a = a1 * a + c1 * b;\n      this.b = b1 * a + d1 * b;\n      this.c = a1 * c + c1 * d;\n      this.d = b1 * c + d1 * d;\n    }\n    this.tx = a1 * tx + c1 * ty + this.tx;\n    this.ty = b1 * tx + d1 * ty + this.ty;\n    return this;\n  };\n}\n"
  },
  {
    "path": "src/utils/processTransform/parseTransformOriginProp.ts",
    "content": "import { LayoutInfo } from '../../types';\n\nconst KEYWORDS: { [keyword: string]: [number, number, number] } = {\n  top: [0.5, 0, 0],\n  bottom: [0.5, 1, 0],\n  left: [0, 0.5, 0],\n  right: [1, 0.5, 0],\n  center: [0.5, 0.5, 0],\n};\n\nfunction isPercentage(token: string) {\n  return token.indexOf('%') !== -1;\n}\n\nexport function parseTransformOriginProp(\n  layout: LayoutInfo,\n  _origin?: string | null,\n): [number, number, number] {\n  const origin = (_origin || '').trim();\n\n  const tokens = origin.split(' ');\n\n  let offsetX: number;\n  let offsetY: number;\n\n  if (tokens.length <= 1) {\n    const keyword = KEYWORDS[tokens[0] || 'center'];\n    if (keyword) {\n      offsetX = keyword[0] * layout.width;\n      offsetY = keyword[1] * layout.height;\n    } else {\n      let value = parseFloat(tokens[0]);\n\n      if (isPercentage(tokens[0])) {\n        value /= 100;\n        offsetX = value * layout.width;\n        offsetY = value * layout.height;\n      } else {\n        offsetX = value;\n        offsetY = value;\n      }\n    }\n  } else {\n    const keywordX = KEYWORDS[tokens[0]];\n    if (keywordX) {\n      offsetX = keywordX[0] * layout.width;\n    } else {\n      let value = parseFloat(tokens[0]);\n\n      if (isPercentage(tokens[0])) {\n        value /= 100;\n        offsetX = value * layout.width;\n      } else {\n        offsetX = value;\n      }\n    }\n\n    const keywordY = KEYWORDS[tokens[1]];\n    if (keywordY) {\n      offsetY = keywordY[1] * layout.height;\n    } else {\n      let value = parseFloat(tokens[1]);\n\n      if (isPercentage(tokens[1])) {\n        value /= 100;\n        offsetY = value * layout.height;\n      } else {\n        offsetY = value;\n      }\n    }\n  }\n\n  return [\n    offsetX - layout.width / 2,\n    offsetY - layout.height / 2,\n    tokens[2] ? parseFloat(tokens[2]) : 0,\n  ];\n}\n"
  },
  {
    "path": "src/utils/processTransform/parseTransformProp.ts",
    "content": "// based on https://github.com/react-native-community/react-native-svg/blob/28235ea137a75097c011f11fee92bec8a97b4afa/lib/extract/extractTransform.js\nimport * as peg from 'pegjs';\nimport { Matrix2D } from './matrix2D';\n\nconst pooledMatrix = new Matrix2D();\n\nconst transformParser = peg.generate(`\n{\n    var deg2rad = Math.PI / 180;\n\n    /*\n      ╔═        ═╗   ╔═        ═╗   ╔═     ═╗\n      ║ al cl el ║   ║ ar cr er ║   ║ a c e ║\n      ║ bl dl fl ║ * ║ br dr fr ║ = ║ b d f ║\n      ║ 0  0  1  ║   ║ 0  0  1  ║   ║ 0 0 1 ║\n      ╚═        ═╝   ╚═        ═╝   ╚═     ═╝\n    */\n    function multiply_matrices(l, r) {\n        var [al, cl, el, bl, dl, fl] = l;\n        var [ar, cr, er, br, dr, fr] = r;\n\n        var a = al * ar + cl * br;\n        var c = al * cr + cl * dr;\n        var e = al * er + cl * fr + el;\n        var b = bl * ar + dl * br;\n        var d = bl * cr + dl * dr;\n        var f = bl * er + dl * fr + fl;\n\n        return [a, c, e, b, d, f];\n    }\n}\n\ntransformList\n    = wsp* ts:transforms? wsp* { return ts; }\n\ntransforms\n    = t:transform commaWsp* ts:transforms\n    {\n        return multiply_matrices(t, ts);\n    }\n    / t:transform\n\ntransform\n    = matrix\n    / translate\n    / scale\n    / rotate\n    / skewX\n    / skewY\n\nmatrix\n    = \"matrix\" wsp* \"(\" wsp*\n        a:number commaWsp\n        b:number commaWsp\n        c:number commaWsp\n        d:number commaWsp\n        e:number commaWsp\n        f:number wsp* \")\"\n    {\n        return [\n            a, c, e,\n            b, d, f\n        ];\n    }\n\ntranslate\n    = \"translate\" wsp* \"(\" wsp* tx:number ty:commaWspNumber? wsp* \")\"\n    {\n        return [\n            1, 0, tx,\n            0, 1, ty || 0\n        ];\n    }\n\nscale\n    = \"scale\" wsp* \"(\" wsp* sx:number sy:commaWspNumber? wsp* \")\"\n    {\n        return [\n            sx, 0,                     0,\n            0,  sy === null ? sx : sy, 0\n        ];\n    }\n\nrotate\n    = \"rotate\" wsp* \"(\" wsp* angle:number c:commaWspTwoNumbers? wsp* \")\"\n    {\n        var cos = Math.cos(deg2rad * angle);\n        var sin = Math.sin(deg2rad * angle);\n        if (c !== null) {\n            var [x, y] = c;\n            return [\n                cos, -sin, cos * -x + -sin * -y + x,\n                sin,  cos, sin * -x +  cos * -y + y\n            ];\n        }\n        return [\n            cos, -sin, 0,\n            sin,  cos, 0\n        ];\n    }\n\nskewX\n    = \"skewX\" wsp* \"(\" wsp* angle:number wsp* \")\"\n    {\n        return [\n            1, Math.tan(deg2rad * angle), 0,\n            0, 1,                         0\n        ];\n    }\n\nskewY\n    = \"skewY\" wsp* \"(\" wsp* angle:number wsp* \")\"\n    {\n        return [\n            1,                         0, 0,\n            Math.tan(deg2rad * angle), 1, 0\n        ];\n    }\n\nnumber\n    = f:(sign? floatingPointConstant) { return parseFloat(f.join(\"\")); }\n    / i:(sign? integerConstant) { return parseInt(i.join(\"\")); }\n\ncommaWspNumber\n    = commaWsp n:number { return n; }\n\ncommaWspTwoNumbers\n    = commaWsp n1:number commaWsp n2:number { return [n1, n2]; }\n\ncommaWsp\n    = (wsp+ comma? wsp*) / (comma wsp*)\n\ncomma\n    = \",\"\n\nintegerConstant\n    = ds:digitSequence { return ds.join(\"\"); }\n\nfloatingPointConstant\n    = f:(fractionalConstant exponent?) { return f.join(\"\"); }\n    / d:(digitSequence exponent) { return d.join(\"\"); }\n\nfractionalConstant \"fractionalConstant\"\n    = d1:digitSequence? \".\" d2:digitSequence { return [d1 ? d1.join(\"\") : null, \".\", d2.join(\"\")].join(\"\"); }\n    / d:digitSequence \".\" { return d.join(\"\"); }\n\nexponent\n    =  e:([eE] sign? digitSequence) { return [e[0], e[1], e[2].join(\"\")].join(\"\"); }\n\nsign\n    = [+-]\n\ndigitSequence\n    = digit+\n\ndigit\n    = [0-9]\n\nwsp\n    = [\\\\u0020\\\\u0009\\\\u000D\\\\u000A]\n`);\n\nfunction appendTransform(transform: string) {\n  if (!transform) {\n    return;\n  }\n  try {\n    const [a, c, e, b, d, f] = transformParser.parse(transform);\n    pooledMatrix.append(a, b, c, d, e, f);\n  } catch (e) {\n    console.error(e);\n  }\n}\n\nfunction transformToMatrix(transform: string, origin: [number, number, number]) {\n  pooledMatrix.reset();\n  pooledMatrix.append(1, 0, 0, 1, -origin[0], -origin[1]);\n  appendTransform(transform);\n  pooledMatrix.append(1, 0, 0, 1, origin[0], origin[1]);\n  return pooledMatrix.toArray();\n}\n\nexport function parseTransformProp(transform: string, origin: [number, number, number]) {\n  return transformToMatrix(transform, origin);\n}\n"
  },
  {
    "path": "src/utils/same.ts",
    "content": "export const same = (a: any, b: any, c: any, d: any) => a === b && b === c && c === d;\n"
  },
  {
    "path": "src/utils/sharedTextStyles/index.sketch.ts",
    "content": "import invariant from 'invariant';\nimport { fromSJSON } from '../../jsonUtils/sketchJson/fromSJSON';\nimport { toSJSON } from '../../jsonUtils/sketchJson/toSJSON';\nimport { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport { SketchDocument, TextStyle } from '../../types';\nimport { generateID } from '../../jsonUtils/models';\nimport { parseTextStyle } from '../../jsonUtils/textLayers';\n\nclass TextStyles {\n  _document: SketchDocument | null;\n\n  constructor() {\n    this._document = null;\n  }\n\n  setDocument(doc?: SketchDocument) {\n    invariant(doc, 'Please provide a sketch document reference');\n\n    this._document = doc;\n    return this;\n  }\n\n  setStyles(styles: Array<any>) {\n    invariant(this._document, 'Please provide a sketch document reference');\n\n    this._document.documentData().layerTextStyles().setObjects(styles);\n\n    return this;\n  }\n\n  addStyle(name: string, style: FileFormat.Style): string {\n    const { _document } = this;\n    invariant(_document, 'Please provide a sketch document reference');\n\n    const nativeStyle = fromSJSON(style, '119');\n\n    const container = _document.documentData().layerTextStyles();\n\n    let sharedStyle: any;\n\n    // Sketch < 50\n    if (container.addSharedStyleWithName_firstInstance) {\n      sharedStyle = container.addSharedStyleWithName_firstInstance(name, nativeStyle);\n    } else {\n      const allocator = MSSharedStyle.alloc();\n      // Sketch 50, 51\n      if (allocator.initWithName_firstInstance) {\n        sharedStyle = allocator.initWithName_firstInstance(name, nativeStyle);\n      } else {\n        sharedStyle = allocator.initWithName_style(name, nativeStyle);\n      }\n\n      container.addSharedObject(sharedStyle);\n    }\n\n    sharedStyle.objectID = generateID(`sharedStyle:${name}`, !!name);\n\n    // NOTE(gold): the returned object ID changes after being added to the store\n    // _don't_ rely on the object ID we pass to it, but we have to have one set\n    // otherwise Sketch crashes\n    return String(sharedStyle.objectID());\n  }\n\n  getStyle(name: string, document?: SketchDocument): TextStyle | undefined {\n    const { _document } = this;\n    const doc = document || _document;\n\n    invariant(doc, 'Please provide a sketch document reference');\n\n    const sharedStyles = doc.documentData().layerTextStyles().objects();\n\n    let foundStyle = undefined;\n    for (let i = 0; i < sharedStyles.length; i++) {\n      if (String(sharedStyles[i].name()) === String(name)) {\n        foundStyle = sharedStyles[i].style();\n      }\n    }\n\n    if (!foundStyle) {\n      return undefined;\n    }\n\n    const style = toSJSON(foundStyle) as FileFormat.Style;\n\n    return parseTextStyle(style);\n  }\n}\n\nexport const sharedTextStyles = new TextStyles();\n"
  },
  {
    "path": "src/utils/sharedTextStyles/index.ts",
    "content": "import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';\nimport { SketchDocument, TextStyle } from '../../types';\nimport { generateID } from '../../jsonUtils/models';\n\nclass TextStyles {\n  setDocument(_doc?: SketchDocument) {\n    return this;\n  }\n\n  setStyles(_styles: Array<any>) {\n    return this;\n  }\n\n  addStyle(name: string, _style: FileFormat.Style): string {\n    return generateID(`sharedStyle:${name}`, !!name);\n  }\n\n  getStyle(_name: string, _document?: SketchDocument): TextStyle | undefined {\n    return undefined;\n  }\n}\n\nexport const sharedTextStyles = new TextStyles();\n"
  },
  {
    "path": "src/utils/sortObjectKeys.ts",
    "content": "export const sortObjectKeys = <T extends { [key: string]: unknown }>(obj: T): T => {\n  const keys = Object.keys(obj).sort();\n  // @ts-ignore\n  const acc: T = {};\n  return keys.reduce((acc, key) => ({ ...acc, [key]: obj[key] }), acc);\n};\n"
  },
  {
    "path": "src/utils/zIndex.ts",
    "content": "import { ReactTestRendererNode } from 'react-test-renderer';\n\n// Sort z-index values lowest to highest\nexport const zIndex = (\n  nodes: (ReactTestRendererNode | string)[],\n): ((ReactTestRendererNode & { oIndex: number }) | string)[] =>\n  nodes\n    .map((node, index) => {\n      if (typeof node === 'string') {\n        return node;\n      }\n      return {\n        ...node,\n        oIndex: index, // Keep track of original index in array\n      };\n    })\n    .sort((a, b) => {\n      const aIndex =\n        typeof a === 'string'\n          ? 0\n          : a.props && a.props.style && a.props.style.zIndex\n          ? a.props.style.zIndex\n          : 0;\n      const bIndex =\n        typeof b === 'string'\n          ? 0\n          : b.props && b.props.style && b.props.style.zIndex\n          ? b.props.style.zIndex\n          : 0;\n      return aIndex - bIndex;\n    });\n"
  },
  {
    "path": "template/.gitignore",
    "content": "# build artifacts\nplugin.sketchplugin/Contents/Sketch\nplugin.sketchplugin/Contents/Resources/_webpack_resources\n\n# npm\nnode_modules\n.npm\nnpm-debug.log\n\n# mac\n.DS_Store\n\n# WebStorm\n.idea\n"
  },
  {
    "path": "template/README.md",
    "content": "# {{ name }}\n\n_This plugin was created using `skpm`. For a detailed explanation on how things work, checkout the [skpm Readme](https://github.com/skpm/skpm/blob/master/README.md)._\n\n## Usage\n\nInstall the dependencies\n\n```bash\nnpm install\n```\n\nOnce the installation is done, you can run some commands inside the project folder:\n\n```bash\nnpm run build\n```\n\nTo watch for changes:\n\n```bash\nnpm run watch\n```\n\nAdditionally, if you wish to run the plugin every time it is built:\n\n```bash\nnpm run render\n```\n\n## Custom Configuration\n\n### Babel\n\nTo customize Babel, you have two options:\n\n- You may create a [`.babelrc`](https://babeljs.io/docs/usage/babelrc) file in your project's root directory. Any settings you define here will overwrite matching config-keys within skpm preset. For example, if you pass a \"presets\" object, it will replace & reset all Babel presets that skpm defaults to.\n\n- If you'd like to modify or add to the existing Babel config, you must use a `webpack.skpm.config.js` file. Visit the [Webpack](#webpack) section for more info.\n\n### Webpack\n\nTo customize webpack create `webpack.skpm.config.js` file which exports function that will change webpack's config.\n\n```js\n/**\n * Function that mutates original webpack config.\n * Supports asynchronous changes when promise is returned.\n *\n * @param {object} config - original webpack config.\n * @param {boolean} isPluginCommand - wether the config is for a plugin command or a resource\n **/\nmodule.exports = function(config, isPluginCommand) {\n  /** you can change config here **/\n};\n```\n\n## Debugging\n\nTo view the output of your `console.log`, you have a few different options:\n\n- Use the [`sketch-dev-tools`](https://github.com/skpm/sketch-dev-tools)\n- Open `Console.app` and look for the sketch logs\n- Look at the `~/Library/Logs/com.bohemiancoding.sketch3/Plugin Output.log` file\n\nSkpm provides a convenient way to do the latter:\n\n```bash\nskpm log\n```\n\nThe `-f` option causes `skpm log` to not stop when the end of logs is reached, but rather to wait for additional data to be appended to the input\n"
  },
  {
    "path": "template/package.json",
    "content": "{\n  \"name\": \"foobar\",\n  \"version\": \"0.1.0\",\n  \"engines\": {\n    \"sketch\": \">=3.0\"\n  },\n  \"skpm\": {\n    \"name\": \"foobar\",\n    \"manifest\": \"src/manifest.json\",\n    \"main\": \"plugin.sketchplugin\"\n  },\n  \"scripts\": {\n    \"build\": \"skpm-build\",\n    \"watch\": \"skpm-build --watch\",\n    \"render\": \"skpm-build --watch --run\",\n    \"render:once\": \"skpm-build --run\",\n    \"postinstall\": \"npm run build && skpm-link\"\n  },\n  \"devDependencies\": {\n    \"@skpm/builder\": \"^0.7.4\"\n  },\n  \"dependencies\": {\n    \"prop-types\": \"^15.5.8\",\n    \"react\": \"^16.3.2\",\n    \"react-sketchapp\": \"^3.0.0\",\n    \"react-test-renderer\": \"^16.3.2\"\n  }\n}\n"
  },
  {
    "path": "template/src/manifest.json",
    "content": "{\n  \"compatibleVersion\": 3,\n  \"bundleVersion\": 1,\n  \"commands\": [\n    {\n      \"name\": \"my-command\",\n      \"identifier\": \"my-command-identifier\",\n      \"script\": \"./my-command.js\"\n    }\n  ],\n  \"menu\": {\n    \"title\": \"foobar\",\n    \"items\": [\"my-command-identifier\"]\n  }\n}\n"
  },
  {
    "path": "template/src/my-command.js",
    "content": "import sketch from 'sketch';\nimport * as React from 'react';\nimport * as PropTypes from 'prop-types';\nimport { render, Artboard, Text, View } from 'react-sketchapp';\n\nconst Swatch = ({ name, hex }) => (\n  <View\n    name={`Swatch ${name}`}\n    style={{\n      height: 96,\n      width: 96,\n      margin: 4,\n      backgroundColor: hex,\n      padding: 8,\n    }}\n  >\n    <Text name=\"Swatch Name\" style={{ color: '#FFF', fontWeight: 'bold' }}>\n      {name}\n    </Text>\n    <Text name=\"Swatch Hex\" style={{ color: '#FFF' }}>\n      {hex}\n    </Text>\n  </View>\n);\n\nconst Color = {\n  hex: PropTypes.string.isRequired,\n  name: PropTypes.string.isRequired,\n};\n\nSwatch.propTypes = Color;\n\nconst Document = ({ colors }) => (\n  <Artboard\n    name=\"Swatches\"\n    style={{\n      flexDirection: 'row',\n      flexWrap: 'wrap',\n      width: (96 + 8) * 4,\n    }}\n  >\n    {Object.keys(colors).map(color => (\n      <Swatch name={color} hex={colors[color]} key={color} />\n    ))}\n  </Artboard>\n);\n\nDocument.propTypes = {\n  colors: PropTypes.objectOf(PropTypes.string).isRequired,\n};\n\nexport default () => {\n  const colorList = {\n    Haus: '#F3F4F4',\n    Night: '#333',\n    Sur: '#96DBE4',\n    'Sur Dark': '#24828F',\n    Peach: '#EFADA0',\n    'Peach Dark': '#E37059',\n    Pear: '#93DAAB',\n    'Pear Dark': '#2E854B',\n  };\n\n  render(<Document colors={colorList} />, sketch.getSelectedDocument().selectedPage);\n};\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es2017\",\n    \"outDir\": \"lib\",\n    \"rootDir\": \"src\",\n    \"moduleResolution\": \"node\",\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"inlineSourceMap\": false,\n    \"esModuleInterop\": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,\n\n    \"strict\": true /* Enable all strict type-checking options. */,\n\n    \"lib\": [\"es5\", \"dom\"],\n    \"types\": [\"jest\", \"node\"],\n    \"typeRoots\": [\"node_modules/@types\", \"src/types\"],\n    \"jsx\": \"react\"\n  },\n  \"include\": [\"src/**/*.ts\"],\n  \"exclude\": [\"node_modules/**\"],\n  \"compileOnSave\": false\n}\n"
  },
  {
    "path": "tsconfig.module.json",
    "content": "{\n  \"extends\": \"./tsconfig\",\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"outDir\": \"lib/module\",\n    \"module\": \"esnext\"\n  },\n  \"exclude\": [\"node_modules/**\"]\n}\n"
  }
]